package httpclient import ( "net" "net/http" "sync" "time" ) // 全局单例变量 var ( once sync.Once // 保证初始化只执行一次 globalClient *http.Client // 复用的 HTTP Client 实例 ) // InitHttpClient 初始化全局 HTTP Client(手动调用,可选) // 配置连接池参数,优化连接复用 func InitHttpClient() { once.Do(func() { // 核心:配置 Transport(连接池核心参数) transport := &http.Transport{ // 全局最大空闲连接数(避免连接数过多) MaxIdleConns: 100, // 空闲连接超时时间(超时后关闭,释放资源) IdleConnTimeout: 30 * time.Second, // 每个目标主机的最大空闲连接数(避免单主机占用过多连接) MaxIdleConnsPerHost: 10, MaxConnsPerHost: 20, // 新增:每个目标主机的最大并发连接数(防止打满服务器) // 禁用压缩(根据业务需求调整,比如调用微信接口可开启) DisableCompression: false, // TCP 连接建立超时(防止连接挂死) DialContext: (&net.Dialer{ Timeout: 10 * time.Second, // 连接建立超时 KeepAlive: 30 * time.Second, // TCP 保活时间(维持长连接) }).DialContext, // TLS 握手超时(HTTPS 场景必配) TLSHandshakeTimeout: 5 * time.Second, /// 等待响应头的超时 ResponseHeaderTimeout: 15 * time.Second, } // 构建 HTTP Client globalClient = &http.Client{ Timeout: 20 * time.Second, // 整个请求的超时(连接+读取+写入) Transport: transport, // 可选:禁用自动重定向(根据业务需求,比如微信接口无需重定向) // CheckRedirect: func(req *http.Request, via []*http.Request) error { // return http.ErrUseLastResponse // }, } }) } // GetClient 获取全局 HTTP Client 实例(推荐使用此方法调用) // 懒加载:如果未初始化,自动触发初始化 func GetClient() *http.Client { InitHttpClient() // 兜底:确保初始化 return globalClient }