1.问题:在使用golang httpclient进行周期性http请求时,偶发性出现eof等报错,http client请求代码如下:
tr := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
client = &http.Client{Transport: tr, Timeout: 60 * time.Second}
简单的初始化一个client,然后进行请求
出现eof。
2.分析:网络搜索出现eof原因有一下几点

我们不存在并发问题排除5,读写超时时间golang均有默认设置排除3,正常多次手动请求结果均正常排除4.由于golang httpclient默认会开启连接复用,那么问题原因应是连接复用问题,如果是客户端主动断了连接,连接池应不能复用该连接除非有bug,另外就是服务端关闭了连接。
测试发现只有在睡眠5秒时会发生报错,小于5秒或者大于5秒均不会报错。检查服务端配置发现其keepalive时间刚好为5秒。
猜想服务端在第5秒时关闭连接,此时客户端刚好发起请求但是连接已关闭导致eof。如此分析http4次挥手
这里服务端主动关闭连接所以为4次挥手发起关闭连接的客户端。由4次挥手可见,客户端发起关闭连接后,服务端处于close_wait状态,并且可以继续发送数据,但是客户端并不会回复,推断这是eof发生的原因。
3.验证
进行抓包验证,如下图
可见237发出FIN包,并且252回应了ACK,此时252处于time_wait,继续发送了一次http请求,由于237此时已经无法响应,触发了eof。
4.结论
解决办法就很简单,周期性请求间隔不为5秒即可规避,但更好的方式是服务端keepalive的时间设得更长一点。同时,golang http客户端可以关闭链接复用,如下: