Gin 框架怎么使用自定義驗(yàn)證器?
1.介紹
Gin 框架自定義驗(yàn)證器,分為字段級別驗(yàn)證器和結(jié)構(gòu)體級別驗(yàn)證器。
其中結(jié)構(gòu)體級別驗(yàn)證器,可以用于跨字段驗(yàn)證,也可以用于和字段級別驗(yàn)證器結(jié)合使用。
需要注意的是,結(jié)構(gòu)體級別驗(yàn)證器的優(yōu)先級小于字段級別驗(yàn)證器。
2.字段級別自定義驗(yàn)證器
定義字段級別驗(yàn)證器
示例代碼:
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
}
閱讀上面這段代碼,我們定義一個(gè) validator.Func 類型的函數(shù)變量,參數(shù)入?yún)⒌念愋褪?validator.FieldLevel,返回結(jié)果是一個(gè) bool 類型的變量。
函數(shù)體中,使用類型斷言,獲取字段的值,然后進(jìn)行邏輯驗(yàn)證。
注冊自定義驗(yàn)證器
示例代碼:
func main() {
r := gin.Default()
// 注冊自定義驗(yàn)證器
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 方法,注冊自定義驗(yàn)證器 userValidator,該方法接收的第一個(gè)參數(shù)是用于結(jié)構(gòu)體字段的 tag 名稱,第二個(gè)參數(shù)是自定義驗(yàn)證器的函數(shù)名稱。
需要注意的是,如果我們注冊的驗(yàn)證器標(biāo)簽名(用于結(jié)構(gòu)體字段的 tag 名稱)已存在,則會被當(dāng)前驗(yàn)證器函數(shù)替換掉。
使用自定義驗(yàn)證器
示例代碼:
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"`
}
閱讀上面這段代碼,我們在請求參數(shù)結(jié)構(gòu)體的字段中,添加我們注冊自定義驗(yàn)證器時(shí)的標(biāo)簽名 user_validator,即可使用自定義驗(yàn)證器。
輸出結(jié)果:
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"
}
3.結(jié)構(gòu)體級別自定義驗(yàn)證器
定義結(jié)構(gòu)體級別驗(yàn)證器
示例代碼:
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", "")
}
}
閱讀上面這段代碼,我們定義一個(gè)函數(shù),該函數(shù)接收一個(gè) validator.StructLevel 類型的參數(shù),函數(shù)體中使用類型斷言,獲取結(jié)構(gòu)體的值,然后進(jìn)行邏輯驗(yàn)證。
注冊自定義驗(yàn)證器
示例代碼:
func main() {
r := gin.Default()
// 注冊自定義驗(yàn)證器
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 方法,注冊自定義驗(yàn)證器 UserStructLevelValidation,該方法接收兩個(gè)參數(shù),分別是 StructLevelFunc 函數(shù)類型的自定義驗(yàn)證器,和需要驗(yàn)證的結(jié)構(gòu)體類型。
使用自定義驗(yàn)證器
示例代碼:
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"`
}
閱讀上面這段代碼,我們不需要在結(jié)構(gòu)體字段標(biāo)簽中有任何操作,即可使用自定義結(jié)構(gòu)體級別的驗(yàn)證器。
以下是結(jié)構(gòu)體級別驗(yàn)證器單獨(dú)使用,和結(jié)合字段級別驗(yàn)證器(標(biāo)簽驗(yàn)證器)一起使用的輸出結(jié)果。
輸出結(jié)果:
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"
}
4.總結(jié)
本文我們介紹 Gin 框架怎么使用自定義驗(yàn)證器,分別列舉了字段級別和結(jié)構(gòu)體級別自定義驗(yàn)證器的使用方式。
需要注意的是,它們并不是線程安全的,需要在任何驗(yàn)證之前,先注冊自定義驗(yàn)證器。