From the official documentation https://golang.org/pkg/net/http/#Client.Do it seems that the RoundTripper may not be able to re-use TCP connection for the next "keep-alive" request if Body is not closed and not fully read. What is this may about?
From what I see Close does not necessarily need to be called, when the whole Body is read. So what is the necessary requirement for connection re-use?
Code snippet (note commented out defer resp.Body.Close()
) which creates multiple connections in a loop and from analysing it with netstat it seems the same TCP connection is used for all connections:
for nextPage != "" {
req, err := http.NewRequest("GET", nextPage, nil)
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", *token))
if err != nil {
panic(err)
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
// defer resp.Body.Close()
result := []*User{}
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
panic(err)
}
nextPage = getNextPage(resp.Header.Get("Link"))
}
Document doesn't say Don't call Close() for keep-alive
. Just say if you want to re-use connection, you MUST call Close() and fully read.
You can only count on what's in the documentation. In some circumstances (go version, OS, architecture, response content length, etc.) it may reuse the connection without fully reading it, or it may not. If you want to ensure the connection will be reused, you must fully read the body and close it.
I generally write a quick helper:
func cleanUpRequest(req *http.Request) {
if req != nil && req.Body != nil {
io.Copy(ioutil.Discard, req.Body)
req.Body.Close()
}
}
This is safe to defer
even before error checking.