В Go у меня есть несколько HTTP-ответов, и я иногда забываю позвонить:
resp.Body.Close()
Что происходит в этом случае? будет утечка памяти? Также безопасно ли вставлять defer resp.Body.Close()
сразу после получения объекта ответа?
client := http.DefaultClient
resp, err := client.Do(req)
defer resp.Body.Close()
if err != nil {
return nil, err
}
Что делать , если есть ошибка, может resp
или resp.Body
быть нулевым?
Ответы:
Это утечка ресурсов. Соединение не будет использоваться повторно и может оставаться открытым, и в этом случае дескриптор файла не будет освобожден.
Нет, следуйте примеру, приведенному в документации, и закройте его сразу после проверки ошибки.
client := http.DefaultClient resp, err := client.Do(req) if err != nil { return nil, err } defer resp.Body.Close()
Из
http.Client
документации:источник
io.LimitReader
. Обычно я использую довольно небольшой лимит, поскольку при слишком большом запросе быстрее установить новое соединение._, err := client.Do(req)
результате дескриптор файла также остается открытым. Таким образом, даже если вам все равно, какой будет ответ, все равно необходимо присвоить его переменной и закрыть тело.Если
Response.Body
не будет закрытClose()
методом, то ресурсы, связанные с fd, не будут освобождены. Это утечка ресурсов.Закрытие
Response.Body
Из источника ответа :
Таким образом, к объекту не привязаны финализаторы, и он должен быть явно закрыт.
Обработка ошибок и отложенная очистка
resp, err := http.Get("http://example.com/") if err != nil { // Handle error if error is non-nil } defer resp.Body.Close() // Close body only if response non-nil
источник
Сначала дескриптор никогда не закрывается, как упоминалось выше.
Более того, golang будет кэшировать соединение (используя
persistConn
struct to wrap) для его повторного использования, если оноDisableKeepAlives
равно false.В golang после использования
client.Do
метода go будет запускатьreadLoop
метод goroutine как один из шагов.Таким образом, в golang http
transport.go
apconn(persistConn struct)
не будет помещен вidleConn
канал до тех пор, пока req не будет отменен вreadLoop
методе, а также этот goroutine (readLoop
метод) будет заблокирован до тех пор, пока req не будет отменен.Вот код, показывающий это.
Если вы хотите узнать больше, вам нужно увидеть
readLoop
метод.источник
См. Https://golang.org/src/net/http/client.go
"Когда err равно nil, resp всегда содержит ненулевое значение resp.Body."
но они не говорят, что когда err! = nil, resp всегда равно nil.
Далее они говорят: «Если resp.Body не закрыт, базовый RoundTripper клиента (обычно Transport) может не иметь возможности повторно использовать постоянное TCP-соединение с сервером для последующего запроса« keep-alive »».
Поэтому я обычно решал проблему следующим образом:
client := http.DefaultClient resp, err := client.Do(req) if resp != nil { defer resp.Body.Close() } if err != nil { return nil, err }
источник