必须显式用json.NewDecoder(c.Request.Body)流式解码,检查err并返回400,defer关闭Body;c.Params.Get无法获取JSON字段,因其只处理查询/路由/表单参数;需严格匹配结构体json标签与Content-Type。

Revel 框架不提供自动 JSON 解析,也不默认绑定请求体字段——你必须显式读取、解码、校验,并手动控制状态码。跳过任一环节,接口就会静默失败、返回 Base64 字符串、或 500 panic。
怎么用 json.NewDecoder 正确解析 POST 的 JSON 请求体
这是最安全、最省内存的方式,直接流式解码,避免 ioutil.ReadAll 提前耗尽 c.Request.Body 导致后续读取为空或二次编码(比如返回 "WyJvbmUiLCJ0d28iLCJ0aHJlZSJd" 这种 Base64)。
- 目标变量类型必须和 JSON 结构严格一致:发
["a","b"]就声明var data []string;发{"id":1,"name":"x"}就用结构体或map[string]interface{} - 调用
decoder := json.NewDecoder(c.Request.Body),再err := decoder.Decode(&data),必须检查err</strong> 并返回 400</li> <li><code>defer c.Request.Body.Close()
是必须的,否则 HTTP/1.1 连接复用可能异常 - 不要在 Decode 前调用
c.Request.ParseForm()或c.Params.ParseBody(c.Request),它们会抢读 Body,导致 Decode 失败
为什么 c.Params.Get 拿不到 JSON 字段
c.Params.Get("xxx") 只查 URL 查询参数、路由参数(:id)和表单数据(application/x-www-form-urlencoded),对 JSON 请求体完全无感知——它根本不会碰 c.Request.Body。
- 常见错误:前端发
{"email":"a@b.com"},后端写email := c.Params.Get("email"),结果永远是空字符串 - 调试时可打印
c.Params.All()确认它确实不含 JSON 字段 - 若混用查询参数和 JSON 体,要分开处理:
c.Params.Get("page")取分页,结构体接收 JSON 主体
嵌套 JSON 和动态结构怎么定义 Go 类型
不能靠猜测字段名或硬塞 map[string]interface{} 就完事。类型定义错一个 tag,整个字段就收不到;结构不固定时又容易 panic。
- 嵌套对象必须逐层定义结构体,且每个字段加
json:标签:type User struct { Profile Profile `json:"profile"` },Profile也要有导出字段+标签 - 字段首字母必须大写才可导出,
UserName string `json:"user_name"`才能匹配前端传的user_name - 遇到键名不确定(如时间戳作 key)或同一字段类型不固定,改用
json.RawMessage延迟解析,避免早期 panic - 类型断言务必加
ok判断:if tags, ok := userMap["tags"].([]interface{}); ok { ... }
Content-Type 不对、空 JSON、非法 JSON 怎么兜底
Revel 不拦截、不默认报错。客户端漏设 Content-Type: application/json,或发 {key: "value"}(缺引号),接口照样走通——直到你访问字段时才发现是零值或 panic。
- 开头检查:
if !strings.Contains(c.Request.Header.Get("Content-Type"), "application/json") { return c.RenderError("415 Unsupported Media Type") } -
decoder.Decode()失败时,err可能是json.SyntaxError、json.UnmarshalTypeError,统一返回 400 并带简明提示 - 空 JSON
{}能成功解码,但所有字段都是零值,业务逻辑需主动判断关键字段是否为零 - 不要忽略
err,生产环境漏掉这一行,就等于把非法输入放行进业务层
最容易被忽略的是:Revel 把 JSON 解析完全交给你控制——没有默认行为、不自动校验、不拦截坏数据。你写的每一行解码逻辑,都得配一行错误检查;每一个结构体字段,都要确认 tag 和前端完全一致;每一次 curl 测试,都得带上 -H "Content-Type: application/json"。少一步,线上就多一个静默失败点。


















