在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
可能为零?
答案 0 :(得分:63)
在这种情况下会发生什么?会有内存泄漏吗?
这是资源泄漏。连接不会被重用,并且可以保持打开状态,在这种情况下文件描述符不会被释放。
获取响应对象后立即放入resp.Body.Close()也是安全的吗?
不,请按照文档中提供的示例进行操作,并在检查错误后立即将其关闭。
client := http.DefaultClient
resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
来自http.Client
文档:
如果返回的错误为nil,则Response将包含一个非零的Body,用户应该关闭它。如果Body未被读取到EOF并且已关闭,则客户端的基础RoundTripper(通常为Transport)可能无法重新使用到服务器的持久TCP连接以用于后续" keep-alive&# 34;请求。
答案 1 :(得分:8)
如果使用Response.Body
方法关闭Close()
,则不会释放与fd相关联的资源。这是资源泄漏。
Response.Body
呼叫者有责任关闭Body。
因此没有绑定到对象的终结器,必须明确关闭它。
出错时,可以忽略任何响应。只有在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
答案 2 :(得分:1)
见https://golang.org/src/net/http/client.go
“当err为nil时,resp总是包含一个非零的resp.Body。”
但他们没有说错误!= nil,resp总是为零。他们继续说:
“如果resp.Body未关闭,则客户端的基础RoundTripper(通常为Transport)可能无法重新使用到服务器的持久TCP连接,以用于后续的”保持活动“请求。”
所以我通常解决了这个问题:
client := http.DefaultClient
resp, err := client.Do(req)
if resp != nil {
defer resp.Body.Close()
}
if err != nil {
return nil, err
}
答案 3 :(得分:1)
首先,描述符永远不会关闭,如上所述。
而且,如果persistConn
为假,golang将缓存连接(使用DisableKeepAlives
struct to wrap)以重用它。
在使用client.Do
方法后的golang中,go将运行goroutine readLoop
方法作为其中一个步骤。
因此,在golang http transport.go
中,pconn(persistConn struct)
将不会被放入idleConn
频道,直到readLoop
方法中的请求被取消,而且此goroutine({ {1}}方法)将被阻止,直到请求被取消。
Here is the code显示它。
如果您想了解更多信息,则需要查看readLoop
方法。
答案 4 :(得分:0)
一种选择是将子请求请求放入新的上下文中,这样您就可以 如果需要,可以使用相同的变量名,而不必担心破坏任何 现有变量,仍然关闭所有内容:
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())
}