Golang中是否需要关闭请求体

Golang中是否需要关闭请求体 在处理REST API时,我们通常确保关闭响应体。然而,一位同事建议请求体也应该被关闭。根据我在各种博客上读到的内容,似乎没有必要显式关闭请求体,因为服务器会自动处理它。

我的问题是:

  1. 是否有必要关闭请求体?如果是: a. 谁负责关闭请求体——客户端还是服务器? b. 我们需要显式关闭请求体,还是它会被客户端/服务器自动关闭?
5 回复

我认为你误解了这个问题。Madhusudan 指的是 req 而不是 resp

尽管在处理 resp 时你的建议很好,但关闭它始终是一个好习惯。

更多关于Golang中是否需要关闭请求体的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


是的,必须关闭它。 类似这样:

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

我认为这是有必要的。 我喜欢像这样发起HTTP请求以复用本地端口。

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

这取决于具体情况。以下是 HTTP/1 的一个示例:

HTTP 服务器: 可以看到,在执行 ServeHTTP 之后,会执行 w.finishRequest(),并在内部关闭请求体。 go1.23.3/src/net/http/server.go:2098 对于响应,这不需要开发者处理。

HTTP 客户端: 对于请求体,它会在 do(req *Request) 内部主动关闭。 go1.23.3/src/net/http/client.go:595 对于响应,这需要开发者手动处理。

在 Go 语言中,需要关闭请求体,但具体责任方取决于上下文。

1. 是否有必要关闭请求体?

是的,需要关闭请求体。虽然服务器在某些情况下会自动处理,但最佳实践是显式关闭以避免资源泄漏。

2. 责任方和关闭方式

a. 谁负责关闭请求体?

  • 客户端:当创建 HTTP 请求并设置请求体(如 POST/PUT 请求)时,客户端负责关闭请求体。
  • 服务器:服务器在处理传入请求时,也应关闭请求体(通常通过读取到 EOF 或显式关闭)。

b. 是否需要显式关闭?

  • 客户端示例:使用 http.NewRequest 创建请求时,如果请求体是 io.ReaderCloser(如 bytes.Buffer 不实现 Close(),但 io.NopCloser 可包装),需确保关闭。但标准库的 http.Post 等辅助函数会自动处理。
  • 服务器示例:服务器应读取请求体到 EOF 或显式关闭。

代码示例

客户端显式关闭请求体:

package main

import (
    "bytes"
    "io"
    "net/http"
)

func main() {
    body := bytes.NewBufferString("example request body")
    req, err := http.NewRequest("POST", "http://example.com", body)
    if err != nil {
        // 处理错误
    }
    // 注意:bytes.Buffer 未实现 Close(),无需关闭。
    // 但如果使用 io.ReadCloser(如文件),需关闭:
    // defer req.Body.Close()
    
    resp, err := http.DefaultClient.Do(req)
    if err != nil {
        // 处理错误
    }
    defer resp.Body.Close() // 响应体必须关闭
}

服务器读取请求体到 EOF(隐式关闭):

package main

import (
    "io"
    "net/http"
)

func handler(w http.ResponseWriter, r *http.Request) {
    // 读取请求体到 EOF,确保资源释放
    body, err := io.ReadAll(r.Body)
    if err != nil {
        http.Error(w, "无法读取请求体", http.StatusBadRequest)
        return
    }
    // 处理 body...
    w.Write([]byte("请求体已处理"))
}

服务器显式关闭请求体(提前返回时):

func handler(w http.ResponseWriter, r *http.Request) {
    defer r.Body.Close() // 确保请求体关闭
    // 处理逻辑...
}

总结

  • 客户端:通常无需显式关闭请求体(标准库辅助函数已处理),但自定义 io.ReaderCloser 时需注意。
  • 服务器:应始终通过读取到 EOF 或 defer r.Body.Close() 关闭请求体。
  • 响应体:必须显式关闭(使用 defer resp.Body.Close())。

遵循这些实践可避免文件描述符泄漏和资源未释放问题。

回到顶部