- 新增 proxyutil 包,统一 HTTP/HTTPS/SOCKS5/SOCKS5H 代理配置逻辑 - SOCKS5H 支持服务端 DNS 解析,避免本地 DNS 泄露 - 移除 ProxyStrict 宽松模式,代理失败直接返回错误不回退直连 - 前端代理管理页面支持 SOCKS5H 协议的添加/编辑/批量导入 - 补充 IPv6 地址和特殊字符密码的边界测试
71 lines
2.0 KiB
Go
71 lines
2.0 KiB
Go
package repository
|
|
|
|
import (
|
|
"net/http"
|
|
"net/url"
|
|
"testing"
|
|
|
|
"github.com/Wei-Shaw/sub2api/internal/config"
|
|
)
|
|
|
|
// httpClientSink 用于防止编译器优化掉基准测试中的赋值操作
|
|
// 这是 Go 基准测试的常见模式,确保测试结果准确
|
|
var httpClientSink *http.Client
|
|
|
|
// BenchmarkHTTPUpstreamProxyClient 对比重复创建与复用代理客户端的开销
|
|
//
|
|
// 测试目的:
|
|
// - 验证连接池复用相比每次新建的性能提升
|
|
// - 量化内存分配差异
|
|
//
|
|
// 预期结果:
|
|
// - "复用" 子测试应显著快于 "新建"
|
|
// - "复用" 子测试应零内存分配
|
|
func BenchmarkHTTPUpstreamProxyClient(b *testing.B) {
|
|
// 创建测试配置
|
|
cfg := &config.Config{
|
|
Gateway: config.GatewayConfig{ResponseHeaderTimeout: 300},
|
|
}
|
|
upstream := NewHTTPUpstream(cfg)
|
|
svc, ok := upstream.(*httpUpstreamService)
|
|
if !ok {
|
|
b.Fatalf("类型断言失败,无法获取 httpUpstreamService")
|
|
}
|
|
|
|
proxyURL := "http://127.0.0.1:8080"
|
|
b.ReportAllocs() // 报告内存分配统计
|
|
|
|
// 子测试:每次新建客户端
|
|
// 模拟未优化前的行为,每次请求都创建新的 http.Client
|
|
b.Run("新建", func(b *testing.B) {
|
|
parsedProxy, err := url.Parse(proxyURL)
|
|
if err != nil {
|
|
b.Fatalf("解析代理地址失败: %v", err)
|
|
}
|
|
settings := defaultPoolSettings(cfg)
|
|
for i := 0; i < b.N; i++ {
|
|
// 每次迭代都创建新客户端,包含 Transport 分配
|
|
transport, err := buildUpstreamTransport(settings, parsedProxy)
|
|
if err != nil {
|
|
b.Fatalf("创建 Transport 失败: %v", err)
|
|
}
|
|
httpClientSink = &http.Client{
|
|
Transport: transport,
|
|
}
|
|
}
|
|
})
|
|
|
|
// 子测试:复用已缓存的客户端
|
|
// 模拟优化后的行为,从缓存获取客户端
|
|
b.Run("复用", func(b *testing.B) {
|
|
// 预热:确保客户端已缓存
|
|
entry := svc.getOrCreateClient(proxyURL, 1, 1)
|
|
client := entry.client
|
|
b.ResetTimer() // 重置计时器,排除预热时间
|
|
for i := 0; i < b.N; i++ {
|
|
// 直接使用缓存的客户端,无内存分配
|
|
httpClientSink = client
|
|
}
|
|
})
|
|
}
|