英文:
When not to close response body
问题
golang要求用户代码关闭http请求的响应体,以释放资源:
client := http.DefaultClient
resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
我的问题是:为什么要设计成这样?有没有不关闭的情况有益?为什么标准库不在client.Do(req)
中为用户关闭连接?
我问这个问题是因为我经常在代码审查中看到这个陷阱。
英文:
golang requires the response body of an http request be closed in user code, to free resources:
client := http.DefaultClient
resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
My question is: why is this the design? Are there situations where not closing is beneficial? Why does the standard library not close the connection within client.Do(req)
for the user?
I ask because this is a gotcha I see fairly frequently reviewing code.
答案1
得分: 4
从服务器接收的内容没有大小限制。你可能正在下载一个非常大的文件。这就是为什么响应中包含一个读取器:这样你就可以流式传输响应。
由于你可以流式传输响应,当你完成时或者对剩余的结果不再感兴趣时,你必须关闭流。当你关闭流时,服务器将知道你不再对接收剩余的流感兴趣,它将有机会进行清理。
英文:
There is no size limit to the content you receive from the server. You may be downloading a very large file. That's why the response contains a reader: so you can stream the response.
Since you can stream the response, you have to close the stream when you are done, or when you are not interested in the rest of the results. When you close the stream, the server will know that you are no longer interested in receiving the rest of the stream, and it will have a chance to clean up.
答案2
得分: 2
关闭读取器的原因已经在@Burak Serdar的答案中解释过了。
有没有不关闭的情况是有益的?为什么标准库不在client.Do(req)中关闭连接?
如果您需要创建一个自定义的客户端,该客户端在返回一个不关闭的读取器的同时包装了Do()方法,那么这可能是有益的。
一个简单的例子:
func main() {
myCustomClient := CustomClient{
client: http.Client{},
}
req,_ := http.NewRequest("GET", "example.com", nil)
res, _ := myCustomClient.Do(req)
defer res.Body.Close()
// (2) 所以你可以在这里读取它
}
type CustomClient struct {
client http.Client
}
func (c CustomClient)Do(req *http.Request)(*http.Response, error){
// 您可以在这里添加一些自定义逻辑,比如添加一些头部信息
// (1) 并返回未关闭的响应
return c.client.Do(req)
}
英文:
Reason for closing the reader is already explained in @Burak Serdar 's answer.
> Are there situations where not closing is beneficial?. Why does the standard library not close the connection within client.Do(req) for the user?
Could be beneficial if you need to create a custom client that wraps Do() while returning a reader that isn't closed.
A simple example:
func main() {
myCustomClient := CustomClient{
client: http.Client{},
}
req,_ := http.NewRequest("GET", "example.com", nil)
res, _ := myCustomClient.Do(req)
defer res.Body.Close()
// (2) so you can read from it here
}
type CustomClient struct {
client http.Client
}
func (c CustomClient)Do(req *http.Request)(*http.Response, error){
// you may add some custom logic here, such as adding some headers
// (1) and return the response without closing it
return c.client.Do(req)
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论