Подтвердить что ты не робот

Что может случиться, если я не закрываю ответ. В голанге?

В golang у меня есть несколько ответов 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 быть nil?

4b9b3361

Ответ 1

Что происходит в этом случае? будет ли утечка памяти?

Это утечка ресурса. Соединение не будет использоваться повторно и может оставаться открытым, в этом случае дескриптор файла не будет освобожден.

Также безопасно помещать в defer resp.Body.Close() сразу после получения объекта ответа?

Нет, следуйте примеру, приведенному в документации, и закройте его сразу после проверки ошибки.

client := http.DefaultClient
resp, err := client.Do(req)
if err != nil {
    return nil, err
}
defer resp.Body.Close()

Из документации http.Client:

Если возвращенная ошибка равна nil, Ответ будет содержать не ноль Тело, которое пользователь должен закрыть. Если тело не одновременно считывается в EOF и не закрывается, клиент, лежащий в основе RoundTripper (обычно Transport), возможно, не сможет повторно использовать постоянное TCP-соединение с сервером для последующего запроса "keep-alive".

Ответ 2

Если Response.Body не будет закрыт методом Close(), ресурсы, связанные с fd, не будут освобождены. Это утечка ресурсов.

Закрытие Response.Body

Из источника ответа:

Это ответственность вызывающего абонента, чтобы закрыть тело.

Таким образом, к объекту не привязаны финализаторы, и он должен быть явно закрыт.

Обработка ошибок и отложенные очистки

В случае ошибки любой ответ может быть проигнорирован. Ответ, отличный от nil, с ошибкой, отличной от nil, возникает только в случае сбоя CheckRedirect, и даже тогда возвращенный 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

Ответ 3

См. https://golang.org/src/net/http/client.go
"Когда err is nil, resp всегда содержит non-nil 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 
}

Ответ 4

Сначала дескриптор никогда не закрывается, как указано выше.

И что еще, golang будет кэшировать соединение (используя persistConn struct to wrap) для повторного использования, если DisableKeepAlives - false.

В golang после использования метода client.Do go будет запускать goroutine readLoop как один из шагов.

Итак, в golang http transport.go, pconn(persistConn struct) не будет помещаться в канал idleConn, пока req не будет отменен в методе readLoop, а также этот goroutine (метод readLoop) будет заблокирован до тех пор, пока req отменен.

Вот код, показывающий его.

Если вы хотите узнать больше, вам нужно увидеть метод readLoop.