ctx.ReadJSON()是唯一可靠的JSON绑定入口,必须确保Content-Type为application/json、字段导出且带json标签,避免重复读Body;表单数据用ctx.ReadForm(),需字段导出并按规则匹配;binding校验需手动配置app.Validator,中间件中不可用结构体自动注入。

ctx.ReadJSON() 是唯一可靠的 JSON 绑定入口
前端发 application/json,就只能走 ctx.ReadJSON(&v)。用 ctx.FormValue("field") 一定为空,因为那是给 application/x-www-form-urlencoded 和 multipart/form-data 准备的;ctx.URLParam() 更只读 query string,跟请求体完全无关。
常见错误现象:结构体字段始终是零值、日志里看到空字符串或默认数字、校验失败却没报错。
- 先确认
Content-Type:调ctx.Request().Header.Get("Content-Type"),必须包含"application/json",否则ReadJSON可能静默失败 - 结构体字段必须导出(首字母大写),且带
json:"field_name"标签,否则绑定不上 - 重复读
Body会 panic:中间件里调了一次ReadJSON,handler 里再调一次,就会报http: read on closed response body - 解决方案只有两个:要么统一收口到中间件 +
ctx.StopExecution()阻断后续;要么全交给 handler 自己读
表单数据用 ctx.ReadForm,但字段映射规则很具体
ctx.ReadForm(&u) 是处理 application/x-www-form-urlencoded 或 multipart/form-data 的推荐方式,但它不靠反射自动猜字段,而是严格按命名规则匹配。
常见错误现象:结构体字段没被赋值、部分字段为零值、上传文件时解析失败。
- struct 字段必须是 exported(首字母大写),比如
Username string,不能是username string - 默认按小写字段名匹配表单 key:
Username→ 匹配username;Email→ 匹配email - 可用
form:"login_name"标签自定义:Username string `form:"login_name"`→ 匹配表单里的login_name - 不支持嵌套结构体自动展开,
Address.Street这类字段得手动从ctx.FormValue("address.street")取
binding 标签不起作用?你可能漏了 app.Validator
binding:"required"、binding:"email"、binding:"min=1,max=100" 这些标签不会自动生效——Iris 不自带校验器,必须手动配置 app.Validator。
常见错误现象:空字符串通过校验、非法邮箱不报错、整数超出范围仍被接受。
- 没设
app.Validator→ReadJSON成功但跳过所有 binding 规则 - 推荐用
go-playground/validator/v10初始化 validator 实例,再赋给app.Validator -
binding:"email"要求字段非空且格式合法;binding:"gte=1,lte=100"对整数有效,但对字符串长度无效(得用min=1,max=100) - 错误必须手动处理:
if err != nil { ctx.StatusCode(400); ctx.JSON(err); return },Iris 不自动拦截
中间件里不能用结构体自动注入,必须手动读
Iris 的结构体自动绑定(如 func(ctx iris.Context, u User))只在 controller handler 生效,中间件里完全不支持。你在中间件里写这种签名,字段 u 永远是零值。
常见错误现象:中间件里取不到用户信息、鉴权逻辑拿不到 token payload、日志记录为空。
- 中间件里只能用
ctx.ReadJSON(&v)或ctx.ReadForm(&v)手动解析 - 若需复用解析结果,建议存进
ctx.Values().Set("parsed_body", &v),handler 里用ctx.Values().Get("parsed_body")取 - 千万别用
ioutil.ReadAll或io.ReadAll手动读Body再传给json.Unmarshal—— 绕过 Iris 封装,失去binding校验和错误上下文 - 中间件末尾别忘了
ctx.Next(),否则后续 handler 根本不执行
app.Validator 没配,导致 binding 形同虚设;二是中间件和 handler 都试图读 Body,结果第二个读直接 panic。这两个点不卡住,结构体绑定永远“看起来能跑,一上线就崩”。


















