Golang validator v10非必填字符串oneof校验空值报错如何解决
运行环境
- Golang版本:1.18.3
- 参数校验依赖库:
github.com/go-playground/validator/v10
需求场景
需要将传入的JSON请求体反序列化加载到嵌套结构体中,再完成全量参数校验。示例传入JSON payload如下:
{ "name": "Duro", "gender": "MALE", "tier": 3, "mobileNumber": "0356874586", "address": { "city": "Tokyo", "street": "Shibaura St" }, "children":[ { "title": "Mr", "lastName": "Takayashi" } ], "isEmployed": false, "requestedAt": "2022-01-10T03:30:12.639Z" }
现有实现代码
结构体定义(user.go)
package main type User struct { Name string `validate:"required"` Gender string `validate:"required,oneof=MALE FEMALE"` Tier *uint8 `validate:"required,eq=0|eq=1|eq=2|eq=3"` MobileNumber string `validate:"required"` Email string Address *Address `validate:"required"` Children []Child `validate:"required,dive"` IsEmployed *bool `validate:"required"` PreferredContactMethod string `validate:"oneof=EMAIL PHONE POST SMS"` RequestedAt time.Time `validate:"required"` } type Address struct { City string `validate:"required"` Street string `validate:"required"` } type Child struct { Title string `validate:"required"` FirstName string LastName string `validate:"required"` }
测试校验逻辑
func TestUserPayload(t *testing.T) { validate := validator.New() var u User err := json.Unmarshal([]byte(jsonData), &u) if err != nil { panic(err) } err := validate.Struct(&u) if err != nil { t.Errorf("error %v", err) } }
问题现象
运行测试时校验失败,返回如下错误信息:
error Key: 'User.PreferredContactMethod' Error:Field validation for 'PreferredContactMethod' failed on the 'oneof' tag
报错根因:JSON payload中未携带preferredContactMethod字段时,Go会为string类型的PreferredContactMethod字段赋类型零值(空字符串),validator默认会对所有配置了校验tag的字段执行规则,空字符串不在oneof指定的枚举值范围内,因此触发校验报错。但该字段并非必填字段,预期逻辑为:字段未传值时不触发校验,传值时才校验值是否属于指定枚举范围。
解决方案
直接在非必填字段的校验规则最前面添加omitempty标识即可,修改后对应字段的tag如下:
PreferredContactMethod string `validate:"omitempty,oneof=EMAIL PHONE POST SMS"`
omitempty规则的作用是:当字段值为当前类型的零值时(string类型零值为空字符串、数值类型为0、指针为nil、切片/数组为nil或长度为0),直接跳过该字段后续所有校验规则,完全匹配非必填字段的校验需求。
可选优化方案
如果业务场景需要区分「客户端未传该字段」和「客户端传了该字段的零值(比如空字符串)」,可以将可选字段的类型改为对应类型的指针:
PreferredContactMethod *string `validate:"omitempty,oneof=EMAIL PHONE POST SMS"`
这种实现下:
- 客户端未传字段时,结构体字段值为
nil,触发omitempty跳过校验 - 客户端传入空字符串时,结构体字段值为指向空字符串的非nil指针,会正常执行
oneof校验,判定空字符串不合法返回错误,适合入参校验严格度要求更高的接口场景。
该规则同样适用于嵌套结构体、切片类型的可选校验:例如如果Children字段不是必填,可将tag写为validate:"omitempty,dive",实现未传值时不校验,传值时深入每个切片元素执行校验的效果。
内容的提问来源于stack exchange,提问作者samme4life
相关产品推荐
相关产品推荐

