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

使用io.NopCloser复用请求体仍遇EOF错误,求排查解决

解决Go-Chi中间件中Request.Body读取后EOF的问题

问题原因

你遇到的EOF错误核心原因是:

  • 替换request.Body为io.NopCloser(bytes.NewBuffer(body))后,authzCheckRequest会读取整个请求体,此时bytes.Buffer的读取指针已移动到字节切片末尾。
  • 请求传递到后续端点处理器时,再次读取request.Body会从末尾开始,直接返回EOF。

解决方案

完成授权校验后,需要重新将request.Body重置为从开头可读的状态,修正后的代码如下:

if request.Body != nil {
    // 读取原始请求体并保存字节切片
    body, err := io.ReadAll(request.Body)
    if err != nil {
        return nil, errors.Annotatef(err, "Failed to read request body")
    }

    // 第一次设置Body,用于授权校验
    request.Body = io.NopCloser(bytes.NewBuffer(body))
    
    // 执行授权校验
    err := authzCheckRequest(request)
    if err != nil {
        w.WriteHeader(http.StatusBadRequest)
        return
    }

    // 校验完成后,重新设置Body,让后续处理器能从头读取
    request.Body = io.NopCloser(bytes.NewBuffer(body))
} else {
    return nil, errors.New("empty body")
}

next.ServeHTTP(writer, request)

优化建议

可以封装辅助函数复用请求体复制逻辑,让代码更整洁:

// copyRequestBody 读取并复制请求体,同时恢复当前请求的Body可读状态
func copyRequestBody(r *http.Request) ([]byte, error) {
    if r.Body == nil {
        return nil, errors.New("empty body")
    }
    body, err := io.ReadAll(r.Body)
    if err != nil {
        return nil, errors.Annotatef(err, "Failed to read request body")
    }
    r.Body = io.NopCloser(bytes.NewBuffer(body))
    return body, nil
}

在中间件中调用:

// 复制请求体
body, err := copyRequestBody(request)
if err != nil {
    return nil, err
}

// 执行授权校验
err = authzCheckRequest(request)
if err != nil {
    w.WriteHeader(http.StatusBadRequest)
    return
}

// 重置Body供后续处理器使用
request.Body = io.NopCloser(bytes.NewBuffer(body))

next.ServeHTTP(writer, request)

关键注意点

  • 每次读取请求体前,要确保request.Body的读取指针处于起始位置;bytes.NewBuffer(body)会创建一个新的、从开头可读的缓冲区,是最稳妥的方式。
  • 不要尝试直接重置现有bytes.Buffer的位置,因为request.Body被包装成io.ReadCloser后,无法直接获取底层的bytes.Buffer实例,重新创建更简单可靠。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 12:43:20