参考链接 https://studygolang.com/articles/3138
func dialTimeout(network, addr string) (net.Conn, error) {
return net.DialTimeout(network, addr, time.Second*POST_REMOTE_TIMEOUT)
}
func DoRequest(URL string) xx, error {
transport := http.Transport{
Dial: dialTimeout,
}
client := http.Client{
Transport: &transport,
}
content := RequestContent{}
// fill content here
postStr, err := json.Marshal(content)
if err != nil {
return nil, err
}
resp, err := client.Post(URL, "application/json", bytes.NewBuffer(postStr))
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
// receive body, handle it
}
运行这段代码一段时间后会发现,该进程下面有一堆ESTABLISHED状态的连接(用lsof -p pid查看某进程下的所有fd),因为每次DoRequest函数被调用后,都会新建一个TCP连接,如果对端不先关闭该连接(对端发FIN包)的话,我们这边即便是调用了resp.Body.Close()函数仍然不会改变这些处于ESTABLISHED状态的连接。
在transport分配时将DisableKeepAlives参数置为true
req, err := http.NewRequest("POST", urlSso, nil)
if err != nil {
scikits.SugarLogger.Error(err)
return userInfo
}
req.Header.Add("User-Agent", "apifox/1.0.0 (https://www.apifox.cn)")
req.Header.Add("Content-Type", "application/json")
req.Header.Add("Cookie", "token="+token)
// `这里请注意,使用 InsecureSkipVerify: true 来跳过证书验证`
client := &http.Client{
Timeout: 10 * time.Second,
Transport: &http.Transport{
// DisableKeepAlives 参数很关键,业务场景是服务A调用B,每次调用都会创建新的http client对象,这样每次请求都会创建一个连接,而我们的接口请求量很大,这样就会创建大量的连接,所以不能够启用连接池进行连接复用。
DisableKeepAlives: true,
TLSClientConfig: &tls.Config{
InsecureSkipVerify: true,
},
}}
res, err := client.Do(req)
if err != nil {
scikits.SugarLogger.Error(err)
return userInfo
}
defer res.Body.Close()
body, err := ioutil.ReadAll(res.Body)
if err != nil {
return userInfo
}
//fmt.Println(string(body))
type structGetCacheUserInfoTmp struct {
Code int `json:"code"`
Data model.User `json:"data"`
}
var data structGetCacheUserInfoTmp
json.Unmarshal(body, &data)
userInfo = data.Data