Golang驗證器之validator是使用詳解

前言

對於HTTP請求,我們要在腦子裡有一個根深蒂固的概念,那就是任何客戶端傳過來的數據都是不可信任的。那麼開發接口的時候需要對客戶端傳提交的參數進行參數校驗,如果提交的參數隻有一個兩個,這樣我們可以簡單寫個if判斷,那麼要是有很多的參數校驗,那麼滿屏都是參數校驗的if判斷,效率不僅低還不美觀,接下來我們介紹一個參數校驗器validator

什麼是validator

Validator 是一個 Golang 的第三方庫,用於對數據進行校驗,常用於 API 的開發中,對客戶端發出的請求數據進行嚴格校驗,防止惡意請求。

安裝

validator包安裝:

go get -u github.com/go-playground/validator/v10

使用方法

導入validator:

import "github.com/go-playground/validator/v10"

validator 應用瞭 GolangStruct Tag Reflect機制,基本思想是:在 Struct Tag 中為不同的字段定義各自類型的約束,然後通過 Reflect 獲取這些約束的類型信息並在校驗器中進行數據校驗。

示例:

package main

import (
	"fmt"
	"github.com/go-playground/validator/v10"
)

type User struct {
	UserName string `json:"user_name" validate:"required"`
	Password string `json:"password" validate:"required,min=6,max=20"`
}
func main() {
	example := User{
		Password: "123",
	}
 
	//實例化驗證器
	validate  := validator.New() 

	errs := validate.Struct(example)
	if errs != nil {
		for _, err := range errs.(validator.ValidationErrors) {
			fmt.Println(err)
		}
	}

}

validator包的驗證提示默認是英文的,輸出如下:

這樣看可能不太清楚,如果需要翻譯成中文則還需安裝驗證提示翻譯包:

go get -u github.com/go-playground/locales
go get -u github.com/go-playground/universal-translator

修改後如下:

package main

import (
	"fmt"
	"github.com/go-playground/locales/zh"
	ut "github.com/go-playground/universal-translator"
	"github.com/go-playground/validator/v10"
	zh_translations "github.com/go-playground/validator/v10/translations/zh"
)

type User struct {
	UserName string `json:"user_name" validate:"required"`
	Password string `json:"password" validate:"required,min=6,max=20"`
}
func main() {
	example := User{
		Password: "123",
	}
	// 中文翻譯器
	uni := ut.New(zh.New())
	trans, _ := uni.GetTranslator("zh")

	//實例化驗證器
	validate  := validator.New()
	// 註冊翻譯器到校驗器
	err := zh_translations.RegisterDefaultTranslations(validate, trans)
	if err!=nil {
		fmt.Println(err)
		return
	}

	errs := validate.Struct(example)
	if errs != nil {
		for _, err := range errs.(validator.ValidationErrors) {
			fmt.Println(err.Translate(trans))
		}
	}

}

執行輸出:

校驗規則

下面列舉一部分我們開發中經常用到的驗證規則,詳細驗證規則可以參考文檔:

https://pkg.go.dev/gopkg.in/go-playground/validator.v10

Tag 說明 示例
required 必填 Field或Struct validate:"required"
omitempty 空時忽略 Field或Struct validate:"omitempty"
len 長度 Field validate:"len=0"
eq 等於 Field validate:"eq=0"
gt 大於 Field validate:"gt=0"
gte 大於等於 Field validate:"gte=0"
lt 小於 Field validate:"lt=0"
lte 小於等於 Field validate:"lte=0"
min 最小值 Field validate:"min=1"
max 最大值 Field validate:"max=2"
required_with 其他字段其中一個不為空且當前字段不為空 Field validate:"required_with=Field1 Field2"
required_without 其他字段其中一個為空且當前字段不為空 Field `validate:“required_without=Field1 Field2”
lowercase 符串值是否隻包含小寫字符 Field validate:"lowercase"
uppercase 符串值是否隻包含大寫字符 Field validate:"uppercase"
email 字符串值包含一個有效的電子郵件 Field validate:"email"
json 字符串值是否為有效的JSON Field validate:"json"
url 符串值是否包含有效的url Field validate:"url"
uri 符串值是否包含有效的 uri Field validate:"uri"
contains 字符串值包含子字符串值 Field validate:"contains=@"
excludes 字符串值不包含子字符串值 字符串值不包含子字符串值 Field validate:"excludes=@"
ip 字符串值是否包含有效的 IP 地址 Field validate:"ip"
datetime 字符串值是否包含有效的日期 Field validate:"datetime"
startswith 字符串以提供的字符串值開始 Field validate:"startswith=abc"
endswith 字符串以提供的字符串值結束 Field validate:"endswith=abc"

跨字段驗證

validator 允許定義跨字段驗證,即:驗證某個字段與其他字段之間的關系。這種驗證實際上分為兩種:

  • 一種是參數字段就是同一個結構體中的平級字段。
  • 另一種是參數字段為結構中其他字段的字段。

驗證語法很簡單,如果是驗證同一個結構中的字段,則在基礎的 Tags 後面添加一個 field 後綴,例如:eqfield 定義字段間的相等(eq)約束。如果是更深層次的字段,在 field 之前還需要加上 cs(Cross-Struct),eq 就變為瞭 eqcsfield。

  • eqfield=Field:必須等於 Field 的值。
  • nefield=Field:必須不等於 Field 的值。
  • gtfield=Field:必須大於 Field 的值。
  • gtefield=Field: 必須大於等於 Field 的值。
  • ltfield=Field:必須小於 Field 的值。
  • ltefield=Field:必須小於等於 Field 的值。
  • eqcsfield=Other.Field:必須等於 struct Other 中 Field 的值。
  • necsfield=Other.Field:必須不等於 struct Other 中 Field 的值。
  • gtcsfield=Other.Field:必須大於 struct Other 中 Field 的值;
  • gtecsfield=Other.Field:必須大於等於 struct Other 中 Field 的值。
  • ltcsfield=Other.Field:必須小於 struct Other 中 Field 的值。
  • ltecsfield=Other.Field:必須小於等於 struct Other 中 Field 的值。

另外還有幾個常用的 Tag:

  • required_with=Field1 Field2:在 Field1 或者 Field2 存在時,必須;
  • required_with_all=Field1 Field2:在 Field1 與 Field2 都存在時,必須;
  • required_without=Field1 Field2:在 Field1 或者 Field2 不存在時,必須;
  • required_without_all=Field1 Field2:在 Field1 與 Field2 都存在時,必須;

錯誤處理

通過看源碼,我們可以看到validator 返回的錯誤有兩種,一種是參數錯誤,一種是校驗錯誤,它們都實現瞭 error 接口。

  • 參數錯誤時,返回 InvalidValidationError 類型;
  • 校驗錯誤時,返回 ValidationErrors 類型。ValidationErrors 是一個錯誤切片,保存瞭每個字段違反的每個約束信息。

所以 validator 校驗返回的結果有 3 種情況:

  • nil:沒有錯誤;
  • InvalidValidationError:輸入參數錯誤;
  • ValidationErrors:字段違反約束。

validator 返回的錯誤有兩種,一種是參數錯誤,一種是校驗錯誤,它們都實現瞭 error 接口。

參數錯誤時,返回 InvalidValidationError 類型;

校驗錯誤時,返回 ValidationErrors 類型。ValidationErrors 是一個錯誤切片,保存瞭每個字段違反的每個約束信息。

所以 validator 校驗返回的結果隻有 3 種情況:

nil:沒有錯誤;

InvalidValidationError:輸入參數錯誤;

ValidationErrors:字段違反約束。

我們可以在程序中判斷 err != nil 時,可以依次將 err轉換為 InvalidValidationErrorValidationErrors 以獲取更詳細的信息:

err := validate.Struct(user)
if err != nil {
    invalid, ok := err.(*validator.InvalidValidationError)
      if ok {
        fmt.Println("param error:", invalid)
        return
    }
    
    validationErrs := err.(validator.ValidationErrors)
    for _, validationErr := range validationErrs {
        fmt.Println(validationErr)
    }
}

小結

通過以上的內容我們瞭解瞭validator一些基本的功能和用法,在我們開發中大大提高瞭開發效率。

validator功能非常豐富,使用較為簡單方便。它的應用非常廣泛,建議瞭解一下。

到此這篇關於Golang驗證器之validator是使用詳解的文章就介紹到這瞭,更多相關Golang validator內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: