Gin框架自帶參數(shù)校驗的使用詳解
gin
框架內(nèi)置參數(shù)驗證,寫在 binging tag
中,如下所示:
type Tag struct { ID int32 `json:"id" binding:"required"` Name string `json:"name" binding:"required"` }
這個驗證器是由 validator
提供的,文檔
常用的操作符:
,
:且,多個驗證之間同時滿足|
:或,滿足其中一個-
:跳過驗證=
:等于
例子來源于官方文檔:
type User struct { FirstName string `binding:"required"` LastName string `binding:"required"` Age uint8 `binding:"gte=0,lte=130"` Email string `binding:"required,email"` // 驗證是否是一個有效的 email 地址 Gender string `binding:"oneof=male female prefer_not_to` // oneof 表示只能是其中之一 可以用 eq=male|eq=female|eq=prefer_not_to 代替 FavouriteColor string `binding:"iscolor"` // iscolor 表示是否是一個有效的顏色值 Addresses []*Address `binding:"required,dive,required"` // dive 對嵌套結(jié)構(gòu)體進行遞歸驗證 } type Address struct { Street string `binding:"required"` City string `binding:"required"` Planet string `binding:"required"` Phone string `binding:"required"` }
在我們?nèi)粘V袝?jīng)常做手機號驗證,但是官方只有一個 e164
的驗證,e164
是國際通用標準(要加區(qū)號),就不太符合國內(nèi)用戶
這就需要自定義驗證器 mobile
,根據(jù)官網(wǎng)提供的例子,實現(xiàn)它也是比較簡單的
自定義驗證器
首先定義一個 ValidateMobile
方法
import ( "regexp" "github.com/go-playground/validator/v10" ) func ValidateMobile(fl validator.FieldLevel) bool { mobile := fl.Field().String() ok, _ := regexp.MatchString(`^1([38][0-9]|14[579]|5[^4]16[6]|7[1-35-8]|9[189])\d{8}$`, mobile) // 用正則去匹配 return ok }
將方法注冊到 validator
中
import ( "github.com/gin-gonic/gin/binding" ) // 從 gin 中獲取到 validator 驗證器,然后注冊 mobile if v, ok := binding.Validator.Engine().(*validator.Validate); ok { _ = v.RegisterValidation("mobile", myvalidator.ValidateMobile) }
自定義驗證器就定義好了,使用的時候就可以這樣寫了
type User struct { Name string `json:"name" binding:"required"` Mobile string `json:"mobile" binding:"required,mobile"` }
錯誤信息翻譯
validator
默認錯誤信息是英文,如果需要翻譯成中文,自己做轉(zhuǎn)換:
- 跳過
json tag
為-
的字段 - 實例化
zh
和en
翻譯包 - 初始化翻譯器
- 注冊翻譯器
- 調(diào)用
InitTrans
,傳入zh
或者en
即可
具體代碼如下:
import ( "fmt" "mxshop_api/order_web/global" "reflect" "strings" "github.com/gin-gonic/gin/binding" "github.com/go-playground/locales/en" "github.com/go-playground/locales/zh" "github.com/go-playground/validator/v10" ut "github.com/go-playground/universal-translator" en_translations "github.com/go-playground/validator/v10/translations/en" zh_translations "github.com/go-playground/validator/v10/translations/zh" ) func InitTrans(local string) (err error) { // 修改 gin 中 validator 實現(xiàn)定制 if v, ok := binding.Validator.Engine().(*validator.Validate); ok { // 將 json tag 作為字段名 v.RegisterTagNameFunc(func(fld reflect.StructField) string { name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0] // 如果 json tag 為 - 則不處理 if name == "-" { return "" } return name }) zhT := zh.New() enT := en.New() // 第一個參數(shù)是備用的語言環(huán)境,后面的參數(shù)是應(yīng)該支持的語言環(huán)境 uni := ut.New(enT, zhT, enT) // 初始化翻譯器 global.Trans, ok = uni.GetTranslator(local) if !ok { return fmt.Errorf("uni.GetTranslator(%s)", local) } switch local { case "en": en_translations.RegisterDefaultTranslations(v, global.Trans) case "zh": zh_translations.RegisterDefaultTranslations(v, global.Trans) default: en_translations.RegisterDefaultTranslations(v, global.Trans) } return } return }
使用:
if err := initialize.InitTrans("zh"); err != nil { panic(err) }
這個翻譯器只能夠翻譯內(nèi)置的錯誤信息,自定義的驗證器需要自己翻譯
比如我們上面定義的 mobile
驗證器,如果驗證失敗,返回的錯誤信息需要我們自己翻譯
參照官方例子,如下代碼:
// 四個參數(shù) // 需要翻譯的字段名 翻譯器實例 翻譯方法 返回錯誤的信息 _ = validator.RegisterTranslation("mobile", global.Trans, func(ut ut.Translator) error { // 翻譯的內(nèi)容 return ut.Add("mobile", "{0} 非法的手機號碼!", true) }, func(ut ut.Translator, fe validator.FieldError) string { // fe.Field() 獲取到的是字段名,而不是 json tag t, _ := ut.T("mobile", fe.Field()) return t })
這樣就可以翻譯自定義的驗證器了,最終代碼如下:
// 注冊驗證器 if v, ok := binding.Validator.Engine().(*validator.Validate); ok { _ = v.RegisterValidation("mobile", myvalidator.ValidateMobile) _ = v.RegisterTranslation("mobile", global.Trans, func(ut ut.Translator) error { return ut.Add("mobile", "{0} 非法的手機號碼!", true) // see universal-translator for details }, func(ut ut.Translator, fe validator.FieldError) string { t, _ := ut.T("mobile", fe.Field()) return t }) }
格式化返回信息
validator
默認返回的錯誤信息是 json tag
,這不是我們希望的
我們希望拋出去的錯誤是結(jié)構(gòu)化的
- 使用
shouldBindJSON
將參數(shù)接寫到對應(yīng)的結(jié)構(gòu)體中 - 如果解析失敗,則斷言這個錯誤為
validator.ValidationErrors
- 如果斷言成功,則將錯誤進行翻譯
- 去掉結(jié)構(gòu)體中的前綴,并生成一個
map
- 將這個
map
拋出去
最終代碼如下:
if err := ctx.ShouldBindJSON(&bannerForm); err != nil { HandleValidatorError(ctx, err) return } func HandleValidatorError(c *gin.Context, err error) { errs, ok := err.(validator.ValidationErrors) if !ok { c.JSON(http.StatusOK, gin.H{ "msg": err.Error(), }) } c.JSON(http.StatusBadRequest, gin.H{ "error": removeTopStruct(errs.Translate(global.Trans)), }) return } func removeTopStruct(fields map[string]string) map[string]string { rsp := map[string]string{} for field, err := range fields { // 去掉結(jié)構(gòu)體中的前綴 {User.mobile: "mobile 非法的手機號碼!"} rsp[field[strings.Index(field, ".")+1:]] = err } return rsp }
錯誤類型在文檔中有說明type FieldError
Tag()
:得到的是你寫的require
、mobile
等Field()
:結(jié)構(gòu)體中定義的字段名Translate()
:翻譯
總結(jié)
validator
能夠滿足我們?nèi)粘5男枨螅?/p>
- 對嵌套結(jié)構(gòu)體進行遞歸驗證
- 自定義驗證器
- 錯誤信息翻譯
- 格式化返回信息
到此這篇關(guān)于Gin框架自帶參數(shù)校驗的使用詳解的文章就介紹到這了,更多相關(guān)Gin參數(shù)校驗內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!