Beego中间件中不能直接使用c.Input.RequestBody,因中间件接收context.Context而非Controller,RequestBody需手动读取并重置Body流,且须校验Method和Content-Type后解析并挂载至ctx.Input.Data供Controller使用。

中间件里不能直接用 c.Input.RequestBody
Beego 的中间件(beego.InsertFilter)接收的是 *context.Context,不是 *Controller,所以没有 c.Input.RequestBody 这种封装好的字段。你看到的 RequestBody 实际是 Controller 初始化时从 ctx.Request.Body 读取并缓存的——但中间件执行时,Body 还没被读过,也尚未触发框架的 copy 逻辑。
如果你在中间件里直接调用 ctx.Request.Body.Read(),后续 Controller 就会读到空内容(HTTP Body 是一次性流),导致 c.Ctx.Input.RequestBody 为空,即使你已在 app.conf 或 main.go 设置了 copyrequestbody = true。
- 必须手动
io.ReadAll(ctx.Request.Body)一次,再用bytes.NewBuffer()把数据塞回ctx.Request.Body - Beego v2+ 要求 Body 必须是
io.ReadCloser类型,不能只用[]byte - 别忘了调用
ctx.Request.Body.Close()前先备份,否则会 panic
解析 JSON 前先校验 Content-Type 和方法
中间件不该对所有请求都尝试解析 JSON。比如静态资源、表单提交或 GET 请求,强行 json.Unmarshal 会返回 invalid character 错误,还可能掩盖真实问题。
- 只处理
ctx.Request.Method == "POST" || ctx.Request.Method == "PUT" || ctx.Request.Method == "PATCH" - 检查
ctx.Request.Header.Get("Content-Type")是否包含"application/json"(注意含; charset=utf-8的情况) - 若不匹配,跳过解析,直接
return,避免干扰正常流程
把解析结果挂载到 context 中供 Controller 使用
中间件本身不处理业务逻辑,它的作用是预处理并透传数据。JSON 解析结果不能存在局部变量里,得写进 ctx.Input.Data 或自定义字段(推荐前者,和 Beego 原生习惯一致)。
- 用
ctx.Input.Data["json_payload"] = payloadMap(map[string]interface{})或结构体指针 - Controller 中通过
c.Ctx.Input.Data["json_payload"]取值,类型断言后使用 - 不要往
c.Data写,那是响应阶段用的,中间件阶段写无效 - 如果 payload 很大(>1MB),建议只解析关键字段(如
trace_id、auth_token),避免内存浪费
为什么不用 Beego 内置的 JSON 绑定?
Beego 的 c.ParseForm() 或自动绑定(如 c.ParseForm(&v))只支持表单编码(application/x-www-form-urlencoded 和 multipart/form-data),对 JSON 完全无感。它不会读 RequestBody,也不会触发 json.Unmarshal。
也就是说:即使你在 Controller 里写了 c.ParseForm(&user),面对 JSON 请求体,user 字段依然全是零值——这和中间件无关,是框架设计决定的。
真正要解析 JSON,只有两条路:在中间件里提前读 + 解析 + 挂载;或在 Controller 里自己调 json.Unmarshal(c.Ctx.Input.RequestBody, &v)。后者更常见,也更可控。中间件适合做鉴权、日志、限流等与 payload 内容弱相关的操作;强依赖 JSON 结构的逻辑,留在 Controller 更稳妥。


















