很多人最开始使用go的http包的时候,都会找一个示例,以下面代码为例
res, err := http.Get(url)
if err != nil {
return false
}
return res.StatusCode == http.StatusOK
这里面其实有两个错误。
我们实际去看 Get的实现会发现,Get使用了包内的变量,他是全局的。
//Clients are safe for concurrent use by multiple goroutines.
var DefaultClient = &Client{}
func Get(url string) (resp *Response, err error) {
return DefaultClient.Get(url)
}
以上三段在不同行,放一起方便看。
首先他是并发安全的,那就大胆的用(废话…)
其次需要注意的是,client是没有初始化超时的,如果使用这个示例去写生产代码,99%的时候都是很正常的。一旦网络抖动,那么就会导致这一个连接一直保持下去。(接下来会发生什么大家都懂了吧,连接数打满,内存持续上升)
并且由于它是单例的(包变量),垃圾收集器不会尝试去清理他,会有空闲的流一直保持着。
所以最好设置超时,最简单的办法就是在项目启动的init设置全局(项目级别)默认的超时
http.DefaultClient.Timeout = time.Minute
其次也可以自己创建新的client去用
client := http.Client{ Timeout: time.Second * 10 }
遇到这类错误
accept4: too many open files; retrying in 1s
可能是缺少了
defer res.Body.Close()
具体defer知识点就不展开咯 ?