Revel框架解析JSON应直接用json.NewDecoder(c.Request.Body)流式解码,避免c.Params.Get()或ioutil.ReadAll;需匹配数据类型、显式关闭Body、检查错误并返回400状态码,且curl测试时必须指定Content-Type: application/json。

Revel 框架处理 JSON 数据的关键在于:别碰 c.Params,也别用 ioutil.ReadAll 先读一遍再解码——它会吃掉请求体,导致后续 json.Decode 读到空数据,甚至把原始字节误当 JSON 返回(比如出现 "WyJvbmUiLCJ0d28iLCJ0aHJlZSJd" 这种 Base64 字符串)。
直接用 json.NewDecoder(c.Request.Body) 流式解析
Revel 的 c.Request.Body 是个 io.ReadCloser,可直接交给标准库的 json.NewDecoder。它按需读取、边流边解,不占额外内存,也不破坏 Body 流状态。
- 目标变量类型必须和 JSON 结构严格匹配:发送
["one","two"]就用[]string;发送{"id":123,"name":"abc"}就定义 struct 或map[string]interface{} - 解码后务必调用
defer c.Request.Body.Close():虽 Revel 通常自动清理,但显式关闭能避免连接复用异常(尤其在高并发或长连接场景) - 错误必须检查并返回明确状态码:
if err != nil { c.Response.Status = 400; return c.RenderError("Invalid JSON") },不能忽略
别用 c.Params.Get() 读 JSON 请求体
c.Params 只聚合了 URL 查询参数、路径参数、表单字段(application/x-www-form-urlencoded)、multipart 数据,**不包含原始 JSON 请求体内容**。对 Content-Type: application/json 的 POST 请求,c.Params.Get("xxx") 一定返回空字符串。
- 如果你看到
c.Params.Get("data")返回空,不是配置漏了,是它本来就不该有 - 想兼容多种输入?得自己判断
c.Request.Header.Get("Content-Type"),再分支处理:JSON 走json.NewDecoder,表单走c.Request.ParseForm() - 混用场景下,不要假设所有参数都在
c.Params里——JSON 是独立通道,得手动开
测试时 curl 要带正确的 Content-Type 和原始 JSON
本地调试最容易栽在这儿:curl 默认发的是 text/plain,Revel 不会把它当 JSON 处理,json.NewDecoder 会直接报错 invalid character。
- 必须显式加
-H "Content-Type: application/json" -
-d后跟的是纯 JSON 字符串,不要加引号包住整个 JSON(比如-d '{"name":"test"}'✅,不是-d '"{\"name\":\"test\"}"'❌) - 示例命令:
curl -X POST http://localhost:9000/kpi/getdata -H "Content-Type: application/json" -d '["a","b","c"]'
最常被忽略的一点:同一个请求体只能被读一次。一旦你误调了 c.Request.Body 上的任何读操作(包括日志打印、中间件预处理、甚至没关的 defer),后续 json.NewDecoder 就会静默失败。所以要么全程只用一次 json.NewDecoder,要么在中间件里做透传,别偷偷消费 Body。


















