A common pattern - calling http.Get and only using the response status - used to silently destroy HTTP/1 connection reuse because net/http required the response body to be fully consumed before reusing the TCP connection. Establishing a new TCP+TLS connection costs several RTTs, so repeatedly opening connections is expensive: a microbenchmark calling getStatus 100 times to index.golang.org took ~710 ms on Go 1.26 but only ~150 ms on Go 1.27. The underlying problem is that HTTP/1 responses are sent sequentially on a byte stream, so the client cannot locate the next response until the previous body is drained; developers worked around this with manual draining (io.Copy/io.CopyN) plus byte and time limits and background goroutines. HTTP/2 is unaffected because it multiplexes independent streams.
Starting in Go 1.27, net/http.Transport automatically and asynchronously drains unread HTTP/1 response bodies up to 256 KB or 50 ms, skipping the work when a Connection: close header makes draining pointless and applying other optimizations. That implements the common manual patterns safely inside the library, avoids needless connection teardown for small or quick-to-drain bodies, and yields large latency wins for typical usage. The recommended practice is now simply to close the response body when finished (defer resp.Body.Close()) and let net/http manage reuse; the exact behavior may be tuned in future releases.
Summary generated by AI from the linked article. hn.today is not affiliated with Hacker News or Y Combinator.