Files
2026-02-27 13:54:01 +08:00

60 lines
2.0 KiB
Go

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
}