在 golang 中多次请求后多次关闭响应体
Close response body multiple times after multiple requests in golang
在, it is pointed out that response.Body should be closed to avoid resource leak. It is also shown in the overview examples in http package godoc.
在我的测试代码中,我发送了多个请求来尝试 API 和
resp, err := http.DefaultClient.Do(req)
在同一个函数中多次。这是一种不好的做法吗?在这种情况下,我是在每个之后写 defer resp.Body.Close()
,还是只写一次?
url := server.URL + "/ticket/add"
reader = strings.NewReader(`{"id": "test1", "detail": "test1"}`)
req, err := http.NewRequest("POST", url, reader)
assert.Nil(t, err)
resp, err := http.DefaultClient.Do(req)
assert.Nil(t, err)
defer resp.Body.Close()
assert.Equal(t, http.StatusCreated, resp.StatusCode)
// add a ticket with same id
reader = strings.NewReader(`{"id": "test1"}`)
req, err = http.NewRequest("POST", url, reader)
assert.Nil(t, err)
resp, err = http.DefaultClient.Do(req)
assert.Nil(t, err)
assert.Equal(t, http.StatusInternalServerError, resp.StatusCode)
一个相关的问题,在服务端,也就是在func(w http.ResponseWriter, r *http.Request)
里面,是否也需要关闭request body?
是的,您需要关闭两个回复。推迟对 resp.Body.Close
的一个调用不会以某种方式影响另一个。 *http.Response
各不相同,都可以延期。
在服务器端,您不需要关闭 Request.Body
-- 从 http.Request
documentation:
// The Server will close the request body. The ServeHTTP
// Handler does not need to.
不好的做法
如果您没有重用 resp
变量,很明显您正在处理不同的响应实例,每个响应实例都必须关闭。
Do sends an HTTP request and returns an HTTP response (instance)...
所以,不好的做法不是发出多个请求,而是对多个响应重复使用同一个变量。它导致代码不明显。并生成永远无法完成的无法访问的对象。
延迟执行
A defer statement pushes a function call onto a list. The list of saved calls is executed after the surrounding function returns.
如果您计划了单个或多个 defer
red 引用同一变量的执行,则只会执行最后分配给变量对象的方法(多次 defer
s)。
关闭Response.Body
It is the caller's responsibility to
close Body.
因此,通常您必须关闭每个 Response.Body
。
垃圾收集和终结(编辑)
垃圾收集器调用绑定到收集对象终结器以关闭文件、连接和执行其他清理操作。并且默认情况下没有终结器绑定到 Body
对象。
您的改进代码段:
// ...a lot of code
resp_one, err := http.DefaultClient.Do(req)
// BTW, `assert.Nil` just returns whether the assertion was successful (bool) not terminates a test.
if assert.Nil(t, err) == true {
defer resp_one.Body.Close()
}
// ...a lot of code
resp_two, err = http.DefaultClient.Do(req)
if assert.Nil(t, err) == true {
defer resp_two.Body.Close()
}
在
在我的测试代码中,我发送了多个请求来尝试 API 和
resp, err := http.DefaultClient.Do(req)
在同一个函数中多次。这是一种不好的做法吗?在这种情况下,我是在每个之后写 defer resp.Body.Close()
,还是只写一次?
url := server.URL + "/ticket/add"
reader = strings.NewReader(`{"id": "test1", "detail": "test1"}`)
req, err := http.NewRequest("POST", url, reader)
assert.Nil(t, err)
resp, err := http.DefaultClient.Do(req)
assert.Nil(t, err)
defer resp.Body.Close()
assert.Equal(t, http.StatusCreated, resp.StatusCode)
// add a ticket with same id
reader = strings.NewReader(`{"id": "test1"}`)
req, err = http.NewRequest("POST", url, reader)
assert.Nil(t, err)
resp, err = http.DefaultClient.Do(req)
assert.Nil(t, err)
assert.Equal(t, http.StatusInternalServerError, resp.StatusCode)
一个相关的问题,在服务端,也就是在func(w http.ResponseWriter, r *http.Request)
里面,是否也需要关闭request body?
是的,您需要关闭两个回复。推迟对 resp.Body.Close
的一个调用不会以某种方式影响另一个。 *http.Response
各不相同,都可以延期。
在服务器端,您不需要关闭 Request.Body
-- 从 http.Request
documentation:
// The Server will close the request body. The ServeHTTP
// Handler does not need to.
不好的做法
如果您没有重用 resp
变量,很明显您正在处理不同的响应实例,每个响应实例都必须关闭。
Do sends an HTTP request and returns an HTTP response (instance)...
所以,不好的做法不是发出多个请求,而是对多个响应重复使用同一个变量。它导致代码不明显。并生成永远无法完成的无法访问的对象。
延迟执行
A defer statement pushes a function call onto a list. The list of saved calls is executed after the surrounding function returns.
如果您计划了单个或多个 defer
red 引用同一变量的执行,则只会执行最后分配给变量对象的方法(多次 defer
s)。
关闭Response.Body
It is the caller's responsibility to close Body.
因此,通常您必须关闭每个 Response.Body
。
垃圾收集和终结(编辑)
垃圾收集器调用绑定到收集对象终结器以关闭文件、连接和执行其他清理操作。并且默认情况下没有终结器绑定到 Body
对象。
您的改进代码段:
// ...a lot of code
resp_one, err := http.DefaultClient.Do(req)
// BTW, `assert.Nil` just returns whether the assertion was successful (bool) not terminates a test.
if assert.Nil(t, err) == true {
defer resp_one.Body.Close()
}
// ...a lot of code
resp_two, err = http.DefaultClient.Do(req)
if assert.Nil(t, err) == true {
defer resp_two.Body.Close()
}