Skip to content

连接池与代理

连接池配置

连接池是 HTTP 客户端性能的关键因素。HTTPC 使用 ConnectionConfig 管理连接池。

go
cfg := httpc.DefaultConfig()

// 连接池参数
cfg.Connection.MaxIdleConns = 100         // 全局最大空闲连接
cfg.Connection.MaxConnsPerHost = 20       // 每主机最大连接数
cfg.Timeouts.IdleConn = 120 * time.Second // 空闲连接保持时间

参数说明

参数默认说明
MaxIdleConns50全局最大空闲连接数
MaxConnsPerHost10每主机最大连接数(含活跃 + 空闲)
IdleConn90s空闲连接超时,超时后关闭
Dial10s建立连接超时
TLSHandshake10sTLS 握手超时
ResponseHeader0禁用(使用 Request 超时)

场景推荐

场景MaxIdleConnsMaxConnsPerHostIdleConn
高并发 API10020120s
常规服务501090s
低频请求10230s
微服务内部501060s

TIP

MaxConnsPerHost 包含活跃连接和空闲连接。超过此限制的新请求会排队等待连接释放。

代理

HTTPC 提供四种代理模式,按优先级自动生效。所有代理配置均在 ConnectionConfig 中设置。

手动代理

通过 ProxyURL 指定固定代理(最高优先级):

go
cfg := httpc.DefaultConfig()
cfg.Connection.ProxyURL = "http://proxy.example.com:8080"

client, _ := httpc.New(cfg)

带认证的代理:

go
cfg.Connection.ProxyURL = "http://user:[email protected]:8080"

TIP

Config.String() 方法会自动脱敏代理 URL 中的用户名和密码。

SOCKS5 代理

go
cfg := httpc.DefaultConfig()
cfg.Connection.ProxyURL = "socks5://proxy.example.com:1080"

系统代理自动检测

启用后自动检测操作系统代理设置,无需手动指定 ProxyURL

go
cfg := httpc.DefaultConfig()
cfg.Connection.EnableSystemProxy = true
平台检测来源
Windows注册表 Internet Settings
macOS系统偏好设置网络代理
Linux环境变量 HTTP_PROXY / HTTPS_PROXY

代理池

当需要跨多个代理 IP 分发请求(爬虫采集、负载分散、IP 轮换),代理池提供自动轮换、被动熔断与按状态码换代理——无需外部组件。

基本用法

go
cfg := httpc.DefaultConfig()
cfg.Connection.ProxyPool = []string{
    "http://proxy1:8080",
    "http://proxy2:8080",
    "http://proxy3:8080",
}
cfg.Connection.ProxyPoolStrategy = httpc.ProxyStrategyRoundRobin // 默认

client, err := httpc.New(cfg)

每个请求自动从池中选择一个代理。支持 httphttpssocks5socks5h 协议。

字段类型默认说明
ProxyPool[]stringnil代理 URL 列表
ProxyPoolStrategyProxyStrategyProxyStrategyRoundRobin选择策略
ProxyFailureThresholdint3(0 回退)连续连接失败熔断阈值
ProxyCooldowntime.Duration30s(0 回退)熔断代理冷却时间
ProxyRotateOnStatus[]intnil触发换代理重试的状态码

选择策略

策略常量说明
轮询ProxyStrategyRoundRobin按顺序循环选择,重试自动落到下一个代理
随机ProxyStrategyRandom从健康代理中均匀随机选取

轮询(默认)在重试时自动选择不同代理 IP——每次重试推进游标,自然落到下一个代理,无需额外配置。

被动熔断

代理池内置被动健康检查。只有连接层失败(dial/TLS)才会触发熔断,HTTP 状态码不会:

text
代理连接失败

失败计数 +1

连续失败 ≥ ProxyFailureThreshold → 熔断(移出轮换)

等待 ProxyCooldown → 半开探测(恢复轮换)

成功 → 重置计数,关闭熔断
首次失败 → 重新熔断
go
cfg.Connection.ProxyFailureThreshold = 5           // 更宽容,容忍偶发抖动
cfg.Connection.ProxyCooldown = 60 * time.Second    // 冷却更久

当所有代理都被熔断时,返回冷却时间最短(最接近恢复)的代理作为兜底,而非直接失败。

状态码轮换

用于 Cloudflare/WAF 等 IP 封锁场景——返回特定状态码时自动换代理重试:

go
cfg := httpc.DefaultConfig()
cfg.Connection.ProxyPool = []string{
    "http://proxy1:8080",
    "http://proxy2:8080",
    "http://proxy3:8080",
}
cfg.Connection.ProxyRotateOnStatus = []int{403}  // 收到 403 时换代理重试
cfg.Retry.MaxRetries = 3                          // 必须启用重试

client, err := httpc.New(cfg)

状态码轮换 ≠ 熔断

ProxyRotateOnStatus 触发的轮换不会熔断代理——IP 封锁往往目标特定(一个代理在 A 站被封,在 B 站可能正常)。熔断仅由连接层失败触发。需 Retry.MaxRetries > 0 才生效。

ProxyRotateOnStatus 设置且代理池有多个代理时,重试预算自动提升至 len(ProxyPool) - 1(受 MaxRetries 上限 10 约束),确保每个代理都有机会被尝试。

代理优先级

同时配置多种代理方式时,按优先级生效:

优先级配置行为
1(最高)ProxyURL始终使用指定代理(单代理模式)
2ProxyPool在代理池中轮换
3EnableSystemProxy自动检测系统代理
4(最低)直连

TIP

若同时设置 ProxyURLProxyPoolProxyURL 生效。要用代理池,请清空 ProxyURL

内置安全

代理相关功能自动处理以下安全细节,无需手动配置:

  • SSRF 豁免:代理主机地址自动加入 SSRF 豁免列表,不会被私有 IP 检查阻断
  • 去重:代理池中相同 host:port 的条目自动合并,避免轮换偏斜和重复计数
  • URL 验证:所有代理 URL 经安全校验(CRLF 注入防护、协议白名单)

完整的字段说明见 配置 API — 代理池

DNS-over-HTTPS

启用 DoH 减少 DNS 解析延迟和防止 DNS 劫持:

go
cfg := httpc.DefaultConfig()
cfg.Connection.EnableDoH = true
cfg.Connection.DoHCacheTTL = 5 * time.Minute

默认 DoH 提供商(按优先级排列):

提供商地址说明
Cloudflare1.1.1.1/dns-query最快,隐私优先
Googledns.google/resolve全球覆盖
AliDNSdns.alidns.com/resolve中国区域优化

TIP

DoH 启用后,DNS 解析结果会缓存 DoHCacheTTL 时间。如果所有 DoH 提供商不可用,会回退到系统 DNS。

HTTP/2

默认启用 HTTP/2(需要 TLS):

go
cfg := httpc.DefaultConfig()
cfg.Connection.EnableHTTP2 = false // 禁用 HTTP/2

HTTP/2 特性:

  • 多路复用:单连接处理多个并发请求
  • 头部压缩:减少重复头传输
  • 服务端推送

对象池复用

HTTPC 内部对引擎响应对象与字符串构建器复用 sync.Pool,减少 GC 压力;Result 则每次请求新建、由 GC 自动回收。

go
result, err := client.Get(url)
if err != nil {
    return err
}
// Result 每次请求新建,GC 自动回收,无需手动释放

高并发场景中,内部对象池复用可显著减少 GC 压力。

并发请求模式

go
func fetchAll(ctx context.Context, urls []string) ([]*httpc.Result, error) {
    results := make([]*httpc.Result, len(urls))
    errs := make([]error, len(urls))

    var wg sync.WaitGroup
    for i, url := range urls {
        wg.Add(1)
        go func(idx int, u string) {
            defer wg.Done()
            result, err := client.Request(ctx, "GET", u)
            results[idx] = result
            errs[idx] = err
        }(i, url)
    }
    wg.Wait()

    for _, err := range errs {
        if err != nil {
            return nil, err
        }
    }
    return results, nil
}

常见问题

问题原因解决方案
大量 TIME_WAIT空闲连接超时太短增大 IdleConn 超时
连接被拒每主机连接数不够增大 MaxConnsPerHost
请求排队等待连接池太小增大 MaxIdleConns
代理不生效ProxyURLProxyPool 同时设置清空 ProxyURL,仅用 ProxyPool
代理频繁熔断ProxyFailureThreshold 太低增大阈值或 ProxyCooldown

完整的性能反模式和优化建议见 性能优化

下一步