60 lines
2.0 KiB
Go
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
|
|
}
|