gin 默认 validator 不支持身份证校验,需手动注册 idcard 自定义规则:调用 validator.registervalidation("idcard", func(fl validator.fieldlevel) bool {...}),并在 gin.default() 后、路由前执行;结构体 tag 写为 validate:"required,idcard";注意空指针、大小写、空格及区划代码时效性问题。

为什么 gin.Default() 的 validator 无法直接校验身份证号
因为 Gin 内置的 validator.v10(通过 go-playground/validator)默认只提供 required、email、len 等通用规则,不包含 idcard 这类业务强相关校验。直接写 json:"id_card" validate:"idcard" 会报错 Key: 'User.IDCard' Error:Field validation for 'IDCard' failed on the 'idcard' tag。
如何注册自定义的 idcard 校验函数
必须手动调用 validator.RegisterValidation 注册,且需在 Gin 初始化 validator 实例后立即执行(通常在 gin.SetMode(gin.ReleaseMode) 后、路由注册前)。否则中间件或绑定时找不到该 tag。
- 校验函数签名必须是
func(fl validator.FieldLevel) bool,返回true表示通过 - 推荐使用现成库如
github.com/gaorx/idcard验证 15/18 位,避免手写校验逻辑出错(比如最后一位校验码计算) - 注册时 tag 名(如
"idcard")要和 struct tag 中一致,区分大小写
// 示例:注册 idcard 校验
v, _ := binding.Validator.Engine().(*validator.Validate)
v.RegisterValidation("idcard", func(fl validator.FieldLevel) bool {
id := fl.Field().String()
return idcard.IsValid(id)
})
struct tag 中怎么写才能触发校验
结构体字段的 validate tag 必须显式包含 idcard,且不能拼错;Gin 默认只对 Bind / ShouldBind 等方法生效,BindJSON 也适用,但 GetQuery 类方法不走 validator。
- 正确写法:
IdCard string `json:"id_card" validate:"required,idcard"` - 错误写法:
validate:"id_card"(这是字段名,不是 tag 名)、validate:"idcard,required"(顺序无关,但缺required时空字符串会跳过 idcard 校验) - 注意:如果字段类型是
*string,空指针会导致fl.Field().String()panic,需先判空
常见失败场景和调试建议
校验失败时 Gin 默认返回 400 + JSON 错误信息,但具体哪条字段失败、为什么失败,容易被掩盖。实际开发中常遇到:
- 18 位号码末位是
X(大写),但输入为小写x→idcard.IsValid返回 false,需提前strings.ToUpper - 前端传了空格或全角字符 → 在 validator 函数里用
strings.TrimSpace清洗再校验 - Gin 版本 ≥ 1.9 时,
binding.Validator.Engine()可能返回nil,需确保已初始化(调用gin.Default()或显式gin.New().Use(gin.Recovery())) - 并发注册多个自定义校验时,不要重复调用
RegisterValidation,会 panic
真正麻烦的是身份证地址码时效性——2023 年以后部分区划代码已变更,但大多数开源库没及时更新,线上校验通过不代表地址真实存在。











