Why does ES1en. Body need to be closed in detail in golang

  • 2020-06-15 09:15:07
  • OfStack

preface

This article mainly introduces the relevant content of ES4en.Body in golang which needs to be closed. It is introduced in detail through the example code, which has a certain reference learning value for you to learn or use golang

[

Body io.ReadCloser

The http Client and Transport guarantee that Body is always non-nil, even on
responses without a body or responses with a zero-length body. It is the caller's
responsibility to close Body. The default HTTP client's Transport does not attempt to
reuse HTTP/1.0 or HTTP/1.1 TCP connections ("keep-alive") unless the Body is read to
completion and is closed.

The http client (Client) and transport (Transport) ensure that the response body is always non-empty, even if there is no response body or zero long response
Body. Closing the response body is the responsibility of the caller. The default http client transport (Transport) does not attempt to reuse es30EN-alive's
http/1.0, http/1.1 connections, unless the request body has been fully read out and closed.

]

Above is the http package documentation. But why does body need to be turned off, and what about closing it? Then read the source code.

To understand body, the first step is to understand how http transactions are handled. http transactions are handled by the underlying Transport.

The first step is to obtain a connection from the connection pool. The function of this connection is realized by three goroutine, one main goroutine, one readLoop, one writeLoop, and the last two goroutine life cycles and connection 1. Although readLoop and writeLoop are called loops (and they are indeed for loops), the fact is that each loop processes an http transaction in its entirety, and the loop itself is only for connection reuse, so the loop structure can be ignored for the sake of understanding its logic.

The next three goroutine coordinate to complete the http transaction:

The master goroutine sends request to both readLoop and writeLoop. writeLoop sends request and then sends the status (error) to the main goroutine and readLoop. readLoop parses the head response and sends the states (error) and response to the master goroutine. The main goroutine returns the user code and readLoop waits for body to finish reading. readLoop recycles connections.

Understand the process of http transactions, then let's go back to the mystery of what is body


// Source code version 1.8.3
// src/net/http/transfer.go:405 body Analytical methods 
func readTransfer(msg interface{}, r *bufio.Reader) (err error)

// src/net/http/transfer.go:485  parsing chunked
t.Body = &body{src: internal.NewChunkedReader(r), hdr: msg, r: r, closing: t.Close}

// src/net/http/transfer.go:490  produce eof
t.Body = &body{src: io.LimitReader(r, realLength), closing: t.Close}

// src/net/http/transport.go:1560  send eof signal 
body := &bodyEOFSignal{

// src/net/http/transport.go:1583 gzip decoding 
resp.Body = &gzipReader{body: body}

body is actually a nested multi-layer ES88en.ES89en:

bufio.Reader, this layer tries to replace multiple small read operations with one large read operation to reduce the number of system calls and improve performance; The connection of ES93en. LimitedReader, tcp will not close after reading body. Continuing reading will cause blocking. chunkedReader, parsing the chunked format encoding (if not chunked skipping); bodyEOFSignal, when you read eof, or when you close body early, you will send a notification to readLoop to reclaim the connection. gzipReader, parsing gzip compression (if not gizp compression omitted);

As you can see above, if body is neither fully read nor closed, the http transaction will not complete this time, and the resource will not be reclaimed unless the connection terminates due to a timeout.

What if the request header or response header indicates Connection: close? Again, it cannot be reclaimed because close indicates that the connection will be disconnected after the http transaction is completed, and the transaction will not be disconnected, much less reclaimed before completion.

Implementation-wise, connections can be recycled as soon as body is read, only when body needs to be discarded, which seems to work without closing. However, body which can be read under normal circumstances, i.e., body 1, will not be read when an error occurs, i.e., body 2. Breaking down situations increases the mental burden of maintainers, so close body is the best option.

conclusion


Related articles: