Gin 框架怎麼使用自定義驗證器?

大家好,我是 frank。「Golang 語言開發棧」公衆號作者。

01  介紹

Gin 框架自定義驗證器,分爲字段級別驗證器和結構體級別驗證器。

其中結構體級別驗證器,可以用於跨字段驗證,也可以用於和字段級別驗證器結合使用。

需要注意的是,結構體級別驗證器的優先級小於字段級別驗證器。

02  字段級別自定義驗證器

定義字段級別驗證器

示例代碼:

var userValidator validator.Func = func(fl validator.FieldLevel) bool {
 val, ok := fl.Field().Interface().(string)
 if ok {
  illegalName := []string{"admin", "Admin", "guest", "Guest"}
  for _, v := range illegalName {
   if v == val {
    return false
   }
  }
 }
 return true
}

閱讀上面這段代碼,我們定義一個 validator.Func 類型的函數變量,參數入參的類型是 validator.FieldLevel,返回結果是一個 bool 類型的變量。

函數體中,使用類型斷言,獲取字段的值,然後進行邏輯驗證。

註冊自定義驗證器

示例代碼:

func main() {
 r := gin.Default()
 // 註冊自定義驗證器
 if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
  err := v.RegisterValidation("user_validator", userValidator)
  if err != nil {
   return
  }
 }
 r.GET("/login", Login)
 err := r.Run()
 if err != nil {
  return
 }
}

閱讀上面這段代碼,我們使用 RegisterValidation 方法,註冊自定義驗證器 userValidator,該方法接收的第一個參數是用於結構體字段的 tag 名稱,第二個參數是自定義驗證器的函數名稱。

需要注意的是,如果我們註冊的驗證器標籤名(用於結構體字段的 tag 名稱)已存在,則會被當前驗證器函數替換掉。

使用自定義驗證器

示例代碼:

func Login(c *gin.Context) {
 user := &User{}
 err := c.ShouldBind(user)
 if err != nil {
  c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
  return
 }
 c.JSON(http.StatusOK, gin.H{
  "data": user,
 })
}

type User struct {
 Name     string `form:"name" binding:"required,user_validator"`
 Password string `form:"password"`
}

閱讀上面這段代碼,我們在請求參數結構體的字段中,添加我們註冊自定義驗證器時的標籤名 user_validator,即可使用自定義驗證器。

輸出結果:

curl -s -X GET http://127.0.0.1:8080/login\?name\=admin\&password\=123456 | jq
{
  "error""Key: 'User.Name' Error:Field validation for 'Name' failed on the 'user_validator' tag"
}

03  結構體級別自定義驗證器

定義結構體級別驗證器

示例代碼:

func UserStructLevelValidation(sl validator.StructLevel) {
 user := sl.Current().Interface().(User)
 if len(user.TrueName) == 0 && len(user.NickName) == 0 {
  sl.ReportError(user.TrueName, "TrueName", "true_name", "true_name_or_nick_name", "")
  sl.ReportError(user.TrueName, "NickName", "nick_name", "true_name_or_nick_name", "")
 }
}

閱讀上面這段代碼,我們定義一個函數,該函數接收一個 validator.StructLevel 類型的參數,函數體中使用類型斷言,獲取結構體的值,然後進行邏輯驗證。

註冊自定義驗證器

示例代碼:

func main() {
 r := gin.Default()
 // 註冊自定義驗證器
 if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
  v.RegisterStructValidation(UserStructLevelValidation, User{})
 }
 r.POST("/register", Register)
 err := r.Run()
 if err != nil {
  return
 }
}

閱讀上面這段代碼,我們使用 RegisterStructValidation 方法,註冊自定義驗證器 UserStructLevelValidation,該方法接收兩個參數,分別是 StructLevelFunc 函數類型的自定義驗證器,和需要驗證的結構體類型。

使用自定義驗證器

示例代碼:

func Register(c *gin.Context) {
 var user User
 err := c.ShouldBind(&user)
 if err != nil {
  c.JSON(http.StatusBadRequest, gin.H{
   "error": err.Error(),
  })
  return
 }
 c.JSON(http.StatusOK, gin.H{
  "data": user,
 })
}

type User struct {
 TrueName string `json:"true_name"`
 NickName string `json:"nick_name"`
 Password string `json:"password" binding:"required"`
}

閱讀上面這段代碼,我們不需要在結構體字段標籤中有任何操作,即可使用自定義結構體級別的驗證器。

以下是結構體級別驗證器單獨使用,和結合字段級別驗證器(標籤驗證器)一起使用的輸出結果。

輸出結果:

curl -s -H "content-type: application/json" -X POST -d '{"true_name": "", "nick_name": "", "password": "123456"}' http://127.0.0.1:8080/register | jq
{
  "error""Key: 'User.TrueName' Error:Field validation for 'TrueName' failed on the 'true_name_or_nick_name' tag\nKey: 'User.NickName' Error:Field validation for 'NickName' failed on the 'true_name_or_nick_name' tag"
}

curl -s -H "content-type: application/json" -X POST -d '{"true_name": "", "nick_name": "", "password": ""}' http://127.0.0.1:8080/register | jq  
{
  "error""Key: 'User.Password' Error:Field validation for 'Password' failed on the 'required' tag\nKey: 'User.TrueName' Error:Field validation for 'TrueName' failed on the 'true_name_or_nick_name' tag\nKey: 'User.NickName' Error:Field validation for 'NickName' failed on the 'true_name_or_nick_name' tag"
}

04  總結

本文我們介紹 Gin 框架怎麼使用自定義驗證器,分別列舉了字段級別和結構體級別自定義驗證器的使用方式。

需要注意的是,它們並不是線程安全的,需要在任何驗證之前,先註冊自定義驗證器。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/8tvXZzHM7tsrPz6LQYA15A