ctx.readjson() 是唯一推荐的 json 请求体绑定方式,它校验 content-type、读取完整 body 并用 json.unmarshal 反序列化;结构体字段必须导出且带正确 json tag,否则为零值;content-type 不匹配或字段未导出会导致 panic、静默失败或零值。

ctx.ReadJSON() 是唯一推荐的 JSON 绑定方式
别用 ctx.JSON() 读请求体——它只负责响应序列化,调用它来“接收数据”会直接 panic 或静默失败。真正绑定 JSON 请求体,必须用 ctx.ReadJSON(&v),它内部做了三件事:检查 Content-Type: application/json、读取完整 body、用 json.Unmarshal 反序列化到结构体指针。没这一步,你拿到的永远是空结构体或零值。
结构体字段必须导出且带 json tag
Go 的 encoding/json 包无法访问小写字段,Iris 不做任何反射魔改。以下写法必然失败:
type LoginReq struct {
username string `json:"username"` // 首字母小写 → 不导出 → ReadJSON 忽略
}
正确写法:
- 字段名首字母大写:
Username string - 显式声明
jsontag:`json:"username"`(注意键名大小写要和请求体完全一致) - 嵌套结构体或切片字段,只要类型匹配、tag 正确,自动递归解析,无需额外配置
常见错误现象和应对条件
这些报错基本都指向同一个根源:请求体格式或结构体定义不匹配。
开箱即用的技能链路由引擎。13 条预定义链覆盖搜索、开发、审查、MLOps、法律、创意等场景,三层路由架构(触发词→SAD反馈→DAG编排),recall@10=96.97%。配置驱动(chains.yaml),零代码扩展。pip install skill-weave-chains 一键安装。
-
invalid character 'e' looking for beginning of value:客户端没发application/json头,或发了空 body / 纯文本(如text/plain)→ 改用ctx.ReadBody()+ 手动json.Unmarshal - 字段值为零值(
"",0,false):结构体字段未导出,或 tag 键名拼写错误(比如请求发"user_name",但 tag 写成`json:"username"`) - 多余字段被静默忽略:这是标准行为,如需严格校验(拒绝未知字段),得配合
go-playground/validator的DisallowUnknownFields选项
什么时候必须换用 ctx.ReadBody()
ctx.ReadJSON() 强制校验 Content-Type,但现实里总有例外。两种场景绕不开 ReadBody:
- 前端 SDK 或测试工具发的是
Content-Type: text/plain,但 body 确实是合法 JSON 字符串 - 你需要先拿到原始字节做签名验签、审计日志或动态路由判断,再决定是否反序列化
示例:
var raw []byte
if err := ctx.ReadBody(&raw); err != nil {
ctx.StatusCode(400)
return
}
// 做完验签后再解码
var req LoginReq
if err := json.Unmarshal(raw, &req); err != nil {
ctx.StatusCode(400)
return
}
注意:ReadBody 不校验类型,也不复用缓冲,频繁调用可能轻微影响性能;而 ReadJSON 的校验和缓冲复用是默认安全收益,别为了省一行代码主动放弃。










