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?
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?
在这种情况下会发生什么?会有内存泄漏吗?
这是资源泄漏。连接不会被重用,可能会保持打开状态,在这种情况下文件描述符将不会被释放。
同时,在获取响应对象后立即使用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,则响应将包含一个非nil的Body,用户需要关闭它。如果Body既没有被读到EOF也没有被关闭,客户端的底层RoundTripper(通常是Transport)可能无法重用持久TCP连接以进行后续的“保持活动”请求。
io.LimitReader
进行包装。我通常使用相当小的限制,因为如果请求太大,建立新连接会更快。 - JimB_, err := client.Do(req)
也会导致文件描述符保持打开状态。因此,即使不关心响应内容,仍然需要将其赋值给变量并关闭 body。 - j boschiero如果Response.Body
没有被Close()
方法关闭,则与fd相关联的资源将不会被释放。这是一种资源泄漏。
Response.Body
根据响应源代码:
关闭Body是调用方的责任。
因此,该对象没有绑定最终器(finalizers),必须显式地关闭。
在出现错误时,可以忽略任何响应。只有在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
首先,与上述提到的内容一样,描述符永远不会关闭。
此外,如果 DisableKeepAlives
为 false,则 Golang 会缓存连接(使用 persistConn
结构进行封装)以便重用。
在 Golang 中,在使用 client.Do
方法后,go 将作为步骤之一运行 goroutine readLoop
方法。
因此,在 golang http transport.go
中,只有当 req 在 readLoop
方法中取消时,pconn(persistConn struct)
才不会被放入 idleConn
通道中,并且此 goroutine(readLoop
方法) 也将被阻塞直到 req 被取消。
这里是代码 显示它。
如果您想了解更多,请查看 readLoop
方法。
请参见https://golang.org/src/net/http/client.go
“当err为nil时,resp始终包含一个非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
}
package main
import (
"bytes"
"net/http"
)
func main() {
b := new(bytes.Buffer)
// request one
r, e := http.Get("http://speedtest.atl.hivelocity.net")
if e != nil {
panic(e)
}
defer r.Body.Close()
b.ReadFrom(r.Body)
// request two
{
r, e := http.Get("http://speedtest.lax.hivelocity.net")
if e != nil {
panic(e)
}
defer r.Body.Close()
b.ReadFrom(r.Body)
}
// print
print(b.String())
}