1. 35
  1.  

  2. 4

    NOTE: Since response bodies are read after the client method has returned you need to use a time.Timer if you want to enforce read time limits.

    I think one would normally use context.WithTimeout to cancel long running body reads.

    If you are not going to do anything with the body then it is still important to read it to completion. To not do so affects the propensity for reuse, particularly if the server is pushing a lot of data. Flush the body with: _, err := io.Copy(ioutil.Discard, res.Body)

    This one is interesting, up until now I’ve always just deferred res.Body.Close and called it a day. Can someone explain to me why it is necessary/preferable to read the response body?

    This is a small one, but as far as I’m concerned, the url.Parse method is essentially infallible and it trips me up all the bloody time. You almost always want url.ParseRequestURI and then some further checks if you are wanting to filter out relative URLs.

    This one bit me a dozen times as well and it’s really suprising for Go newbies that expect a request.URL to be fully populated, i.e. having a scheme, host and what not.

    1. 4

      Basically you send a request and get a response, and with http keepalive you can do that a number of times. If you don’t fully receive the response, you can’t reuse the connection and send another request.

      1. 4

        So, what exactly happens if you don’t read the entire body but you do close it? The original article sort of implies that closing the body is enough in some cases, not just cases where the response is zero bytes.

        These parts confuse me:

        As a client you might not care about the content of your response bodies […] So, to close things out safely the following suffices:

        If I don’t care about the contents of the body, closing suffices? It doesn’t seem so.

        If you are not going to do anything with the body then it is still important to read it to completion. To not do so affects the propensity for reuse, particularly if the server is pushing a lot of data.

        How does the server pushing lots of data affect anything? If the response body is small, but I don’t read it, will the connection somehow become reusable earlier than if the response body is large?

        I would expect that either the response body must be read to reuse the connection at all, or that reading the entire body is never required. Not some halfway thing where sometimes not reading the body still allows reuse, sometimes it doesn’t.

        The official Go docs are also ambiguous here:

        If the Body is not both read to EOF and closed, the Client’s underlying RoundTripper (typically Transport) may not be able to re-use a persistent TCP connection to the server for a subsequent “keep-alive” request.

        1. 3

          What happens depends on whether things are speaking HTTP/1.1 or HTTP/2.

          If you close the body without reading it on an HTTP/1.1 connection, then basically that socket is done with. Resources are neither leaked nor re-used. With HTTP/2 there may be other options and the behavior might be better. If the behavior were otherwise (for example .Close() reads and discards data), that would imply that a server could force your client to download arbitrary amounts of data which would be bad.

          The dual support of http/1.1 and http/2 is, I believe, the source of the ambiguity in the docs.

        2. 2

          Thanks, that was pretty clear!