gin 识别校验需使用 binding 标签,如 binding:"required",不写则跳过校验;shouldbind 按 content-type 自动选择解析方式,shouldbindjson 强制解析 json;校验错误需断言 validator.validationerrors 获取字段级详情。

结构体标签里写什么才能被 Gin 识别校验
Gin 默认只认 binding 标签,且必须显式指定规则,比如 binding:"required" 或 binding:"required,email"。不写 binding 就完全跳过校验,哪怕字段名和请求参数一致也不会触发。常见错误是误用 json 标签替代,比如写成 json:"email" validate:"email" —— Gin 不看 validate,也不自动读 json 名做绑定来源。
实际绑定时,Gin 默认按 json 标签名匹配请求体字段(POST JSON),按 URL 查询参数名匹配 form 标签(GET 查询或表单提交)。若两者都未指定,则 fallback 到结构体字段名(首字母大写),但大小写敏感且不推荐依赖。
-
binding:"required"是最简必要项,缺它整个字段不参与校验 - 多个规则用逗号分隔,如
binding:"required,max=10",顺序无关 - 空字符串、零值、nil 都会触发
required失败,除非加omitempty(但omitempty不影响校验逻辑,只影响序列化) - 自定义错误消息需配合
Msg或中间件统一处理,标签里不能写提示文本
Gin 的 ShouldBind 和 ShouldBindJSON 有什么区别
本质区别在于解析源头和默认行为:ShouldBindJSON 强制只从请求体(Body)读取并解析为 JSON;ShouldBind 是智能路由:根据 Content-Type 自动选解析方式(application/json → JSON,application/x-www-form-urlencoded 或 multipart/form-data → 表单,GET 请求 → 查询参数),再按结构体标签里的 form、json 或字段名做字段映射。
- 用
ShouldBindJSON但前端发的是表单数据?直接报invalid character错误 - 用
ShouldBind但结构体没写form标签,而请求是POST /?id=123?它会尝试从查询参数绑,但字段若叫ID而标签是json:"id",可能因大小写或无匹配标签失败 -
ShouldBind在 multipart 场景下,文件字段必须用form标签且类型为*multipart.FileHeader,否则绑定为空
校验失败时怎么拿到具体是哪个字段错了
Gin 的 err 是 validator.ValidationErrors 类型,可断言后遍历每个错误项,提取字段名、实际值、失败规则。别直接打印 err.Error() —— 那是合并后的字符串,没法结构化处理。
if err := c.ShouldBind(&req); err != nil {
if errors, ok := err.(validator.ValidationErrors); ok {
for _, e := range errors {
// e.Field() 返回结构体字段名,如 "Email"
// e.Tag() 返回触发的校验规则,如 "required"
// e.Value() 返回传入的原始值,注意可能是 nil 或空字符串
log.Printf("field %s failed %s with value %+v", e.Field(), e.Tag(), e.Value())
}
}
}
- 字段名来自结构体定义名(非
json标签名),所以Email string `json:"email" binding:"required"`中e.Field()是"Email",不是"email" -
e.Param()可取规则参数,比如max=10里的"10",用于动态提示 - 若用指针字段(如
*string),e.Value()可能是nil,需判空再取值
嵌套结构体和切片字段的 binding 怎么写才有效
嵌套结构体默认不自动递归校验,必须在父字段上加 binding:"required" 并确保子结构体字段也有 binding 标签;切片字段则需明确声明长度限制或元素校验规则,否则 required 只检查切片是否为 nil,不检查内部元素。
- 嵌套示例:
User *UserReq `json:"user" binding:"required"`,且UserReq内每个字段都要有binding,否则子字段不校验 - 切片示例:
Tags []string `json:"tags" binding:"required,min=1,dive,required"`——dive是关键,表示进入切片每个元素执行后续规则(这里每个元素都不能为空) - map 字段不支持直接 binding,需转为结构体或手动校验
- 时间字段如
time.Time接收字符串时,需配合time_format规则(如binding:"required,time_format=2006-01-02"),否则解析失败不报具体原因
最常被忽略的是 dive:没有它,切片或 map 的元素级校验根本不会触发,看起来像“校验没生效”。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











