You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何检查完HTTP请求体r.Body后必须关闭?不关闭会有何影响?

为什么必须关闭HTTP请求的r.Body?

这个问题问得特别实在——很多刚上手Go HTTP开发的同学都会忽略r.Body的关闭操作,这里面其实藏着不少容易踩的坑,咱们慢慢说清楚。

不关闭r.Body会有什么后果?

  • 连接池资源浪费,性能暴跌:Go的HTTP客户端和服务器端都默认使用连接池来复用TCP连接。如果r.Body没被关闭,这个连接会被标记为“正在使用”,没法放回连接池里重复利用。高并发场景下,很快就会因为新建连接过多导致系统资源耗尽,服务响应变慢甚至直接挂掉。
  • 内存泄漏风险:如果请求体比较大(比如上传文件、提交大表单),未关闭的r.Body会让内存里的缓冲区一直被占用,GC没法及时回收。长期运行下来,服务的内存占用会越来越高,最终引发OOM(内存溢出)。
  • 服务器端资源闲置:如果服务器这边没关闭r.Body,即使已经处理完请求,底层的连接资源也没法及时释放,会一直占用服务器的文件描述符和内存,拖慢整体服务的处理能力。

为什么一定要关闭r.Body?

  • 首先,r.Body实现了io.ReadCloser接口——Go语言里有个不成文的规则:只要是实现了Closer接口的资源,用完就必须关闭,这是资源管理的基本准则,和你打开文件后要关闭是一个道理。
  • 不管你有没有把r.Body的内容读完,都得关闭它。比如有时候json.Decoder成功解析了请求体,但可能请求体里还有剩余的字节没被读取,这时候关闭r.Body会确保这些剩余资源被彻底释放。
  • 还有个容易踩的坑:关闭操作一定要尽早放!像你代码里把defer r.Body.Close()放在Decode之后,如果Decode出错直接return,那这个defer根本不会执行,r.Body就没被关闭。正确的做法是把defer放在函数最开头,确保无论请求处理成功还是失败,都会执行关闭操作。

举个修正后的代码例子:

func createFeedback(w http.ResponseWriter, r *http.Request) {
    defer r.Body.Close() // 放在函数开头,保证任何分支都会执行关闭
    // ... 初始化逻辑 ...
    f := feedback.New()
    if err := json.NewDecoder(r.Body).Decode(f); err != nil {
        http.Error(w, err.Error(), http.StatusBadRequest)
        return
    }
    // ... 后续业务逻辑 ...
}

简单总结一下:关闭r.Body是Go HTTP开发的必备最佳实践,核心就是为了避免资源泄漏、保证连接池的高效复用,别因为偷懒或者疏忽给自己挖了性能或稳定性的坑。

内容的提问来源于stack exchange,提问作者Alex

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 07:07:29