validator.v9: gopkg.in/go-playground/validator.v9
自定義驗證功能
可以添加自定義驗證功能。例:
package main import ( "fmt" "gopkg.in/go-playground/validator.v9" ) type User struct { Name string `validate:"is-zhou"` } func (u *User) userValidator() error { //自定義的驗證函數, validata := validator.New() validata.RegisterValidation("is-zhou", ValidateMyVal) //注冊驗證字段和字段驗證的功能 err := validata.Struct(u) return err } func ValidateMyVal(f1 validator.FieldLevel) bool { //驗證字段的方法的定義 return f1.Field().String() == "zhou" } func main() { user1 := &User{ Name: "aaa", } err := user1.userValidator() //調用自定義驗證過函數 fmt.Println(err, "err1") user2 := &User{ Name: "zhou", } err = user2.userValidator() fmt.Println(err, "err2") }
運行結果
Key: 'User.Name' Error:Field validation for 'Name' failed on the 'is-zhou' tag err1 <nil> err2
跨字段驗證(沒看懂)
跨字段驗證可以通過以下標簽完成:
- eqfield - nefield - gtfield - gtefield - ltfield - ltefield - eqcsfield - necsfield - gtcsfield - gtecsfield - ltcsfield - ltecsfield
但是,如果需要某些自定義跨字段驗證,則可以使用自定義驗證來完成。
為什么不只是有跨字段驗證標簽(即只有eqcsfield而不是eqfield)?
原因是效率。如果要檢查同一結構中的字段“eqfield”,只需在同一結構(1級)上找到該字段。但是,如果我們使用“eqcsfield”,它可能會降低多個級別。例:
type Inner struct { StartDate time.Time } type Outer struct { InnerStructField *Inner CreatedAt time.Time `validate:"ltecsfield=InnerStructField.StartDate"` } now := time.Now() inner := &Inner{ StartDate: now, } outer := &Outer{ InnerStructField: inner, CreatedAt: now, } errs := validate.Struct(outer) // 注意:調用validate.Struct(val)時,topStruct將是傳遞給函數的頂級結構, // 當調用validate.VarWithValue(val,field,tag)時,val將是你傳遞的任何東西,比如: struct,field ...... // 當調用validate.Field(field,tag)時,val將為nil
多個驗證器
字段上的多個驗證器將按定義的順序處理。例:
ype Test struct { Field `validate:"max=10,min=1"` } // 先驗證max,然后才驗證min
錯誤的驗證不會處理,例如:
type Test struct { Field `validate:"min=10,max=0"` } // this definition of min max will never succeed
使用驗證器標簽:
跨字段驗證僅比較同一結構上的字段。如果需要不同結構不同字段比較驗證,您應該實現自己的自定義驗證器。
逗號(“,”)是驗證標記的默認分隔符。如果你希望在參數中包含一個逗號(即excludesall =,),你將需要使用UTF-8十六進制表示0x2C,它在代碼中被替換為逗號,因此上面將變為excludesall = 0x2C。
type Test struct { Field `validate:"excludesall=,"` // 錯誤用法,不能包含逗號 Field `validate:"excludesall=0x2C"` // 正確用法,使用UTF-8十六進制表示 }
管道(“|”)是'或'驗證標簽的分隔符。如果您希望在參數中包含管道,即excludesall = |你將需要使用UTF-8十六進制表示0x7C,它在代碼中被替換為管道,所以上面將成為excludesall = 0x7C
type Test struct { Field `validate:"excludesall=|"` // BAD! Do not include a a pipe! Field `validate:"excludesall=0x7C"` // GOOD! Use the UTF-8 hex representation. }
Baked In Validators and Tags
以下是當前內置驗證器的列表:
- //忽略字段,告訴驗證跳過這個struct字段;這對於忽略嵌入式結構的驗證尤其方便。 (用法: - ) structonly //當遇到嵌套結構的字段並包含此標志時,將運行嵌套結構上的任何驗證,但不會驗證任何嵌套結構字段。如果您在程序內部知道結構有效,但需要驗證它是否已分配,這非常有用。注意:結構本身只能使用“required”和“omitempty”。 nostructlevel //與structonly標記相同,但不會運行任何結構級別驗證。 omitempty //允許條件驗證,例如,如果字段未設置值(由“required”驗證器確定),則其他驗證(如min或max)將不會運行,但如果設置了值,則驗證將運行。 dive //這告訴驗證者潛入切片,數組或映射,並使用后面的驗證標記驗證切片,數組或映射的該級別。還支持多維嵌套,您希望dive的每個級別都需要另一個dive標簽。dive有一些子標簽,'keys'和'endkeys',請參閱下面的keys和endkeys部分
----
required //這將驗證該值不是數據類型的默認零值。數字不為0,字符串不為 " ", slices, maps, pointers, interfaces, channels and functions 不為 nil isdefault //這驗證了該值是默認值,幾乎與所需值相反。 len=10 //對於數字,長度將確保該值等於給定的參數。對於字符串,它會檢查字符串長度是否與字符數完全相同。對於切片,數組和map,驗證元素個數。 max=10 //對於數字,max將確保該值小於或等於給定的參數。對於字符串,它會檢查字符串長度是否最多為該字符數。對於切片,數組和map,驗證元素個數。 min=10 eq=10 //對於字符串和數字,eq將確保該值等於給定的參數。對於切片,數組和map,驗證元素個數。 ne=10 //和eq相反 oneof=red green (oneof=5 7 9) //對於字符串,整數和uint,oneof將確保該值是參數中的值之一。參數應該是由空格分隔的值列表。值可以是字符串或數字。 gt=10 //對於數字,這將確保該值大於給定的參數。對於字符串,它會檢查字符串長度是否大於該字符數。對於切片,數組和map,它會驗證元素個數。 gt //對於time.Time確保時間值大於time.Now.UTC() gte=10 //大於等於 gte //對於time.Time確保時間值大於或等於time.Now.UTC() lt=10 //小於 lt //對於time.Time確保時間值小於time.Now.UTC() lte=10 //小於等於 lte //對於time.Time確保時間值小於等於time.Now.UTC()
----
unique //對於數組和切片,unique將確保沒有重復項。對於map,unique將確保沒有重復值。 alpha //這將驗證字符串值是否僅包含ASCII字母字符 alphanum //這將驗證字符串值是否僅包含ASCII字母數字字符 alphaunicode //這將驗證字符串值是否僅包含unicode字符 alphanumunicode //這將驗證字符串值是否僅包含unicode字母數字字符 numeric //這將驗證字符串值是否包含基本數值。基本排除指數等...對於整數或浮點數,它返回true。 hexadecimal //這將驗證字符串值是否包含有效的十六進制 hexcolor //這驗證字符串值包含有效的十六進制顏色,包括#標簽(#) rgb //這將驗證字符串值是否包含有效的rgb顏色 rgba //這將驗證字符串值是否包含有效的rgba顏色 hsl //這將驗證字符串值是否包含有效的hsl顏色 hsla //這將驗證字符串值是否包含有效的hsla顏色 email //這驗證字符串值包含有效的電子郵件這可能不符合任何rfc標准的所有可能性,但任何電子郵件提供商都不接受所有可能性 file //這將驗證字符串值是否包含有效的文件路徑,並且該文件存在於計算機上。這是使用os.Stat完成的,它是一個獨立於平台的函數。 url //這會驗證字符串值是否包含有效的url這將接受golang請求uri接受的任何url,但必須包含一個模式,例如http://或rtmp:// uri //這驗證了字符串值包含有效的uri。這將接受uri接受的golang請求的任何uri base64 //這將驗證字符串值是否包含有效的base64值。雖然空字符串是有效的base64,但這會將空字符串報告為錯誤,如果您希望接受空字符串作為有效字符,則可以將此字符串與omitempty標記一起使用。 base64url //這會根據RFC4648規范驗證字符串值是否包含有效的base64 URL安全值。盡管空字符串是有效的base64 URL安全值,但這會將空字符串報告為錯誤,如果您希望接受空字符串作為有效字符,則可以將此字符串與omitempty標記一起使用。 btc_addr //這將驗證字符串值是否包含有效的比特幣地址。檢查字符串的格式以確保它匹配P2PKH,P2SH三種格式之一並執行校驗和驗證 btc_addr_bech32 //這驗證了字符串值包含bip-0173定義的有效比特幣Bech32地址(https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki)特別感謝Pieter Wuille提供的參考實現。 eth_addr //這將驗證字符串值是否包含有效的以太坊地址。檢查字符串的格式以確保它符合標准的以太坊地址格式完全驗證被https://github.com/golang/crypto/pull/28阻止 contains=@ //這將驗證字符串值是否包含子字符串值 containsany=!@#? //這將驗證字符串值是否包含子字符串值中的任何Unicode code points。 containsrune=@ //這將驗證字符串值是否包含提供的符文值。 excludes=@ //這驗證字符串值不包含子字符串值。 excludesall=!@#? //這將驗證字符串值在子字符串值中是否包含任何Unicode code points。 excludesrune=@ //這將驗證字符串值是否包含提供的符文值。
-----
isbn //這將驗證字符串值是否包含有效的isbn10或isbn13值。 isbn10 //這將驗證字符串值是否包含有效的isbn10值。 isbn13 //這將驗證字符串值是否包含有效的isbn13值。 uuid //這將驗證字符串值是否包含有效的UUID。 uuid3 //這將驗證字符串值是否包含有效的版本3 UUID。 uuid4 //這將驗證字符串值是否包含有效的版本4 UUID。 uuid5 //這將驗證字符串值是否包含有效的版本5 UUID。
-----
ascii //這將驗證字符串值是否僅包含ASCII字符。注意:如果字符串為空,則驗證為true printascii //這將驗證字符串值是否僅包含可打印的ASCII字符。注意:如果字符串為空,則驗證為true。 multibyte //這將驗證字符串值是否包含一個或多個多字節字符。注意:如果字符串為空,則驗證為true datauri //這將驗證字符串值是否包含有效的DataURI。注意:這也將驗證數據部分是否有效base64 latitude //這將驗證字符串值是否包含有效的緯度。 longitude //這將驗證字符串值是否包含有效經度。 ssn //這將驗證字符串值是否包含有效的美國社會安全號碼。 ip //這將驗證字符串值是否包含有效的IP地址 ipv4 //這將驗證字符串值是否包含有效的v4 IP地址 ipv6 //這將驗證字符串值是否包含有效的v6 IP地址 cidr //這將驗證字符串值是否包含有效的CIDR地址 cidrv4 //這將驗證字符串值是否包含有效的v4 CIDR地址 cidrv5 //這將驗證字符串值是否包含有效的v5 CIDR地址 tcp_addr //這將驗證字符串值是否包含有效的可解析TCP地址 tcp4_addr //這將驗證字符串值是否包含有效的可解析v4 TCP地址 tcp6_addr //這將驗證字符串值是否包含有效的可解析v6 TCP地址 udp_addr //這將驗證字符串值是否包含有效的可解析UDP地址 udp4_addr //這將驗證字符串值是否包含有效的可解析v4 UDP地址 udp6_addr //這將驗證字符串值是否包含有效的可解析v6 UDP地址 ip_addr //這將驗證字符串值是否包含有效的可解析IP地址 ip4_addr //這將驗證字符串值是否包含有效的可解析v4 IP地址 ip6_addr //這將驗證字符串值是否包含有效的可解析v6 IP地址 unix_addr //這將驗證字符串值是否包含有效的Unix地址
------
mac //這將驗證字符串值是否包含有效的MAC地址 //注意:有關可接受的格式和類型,請參閱Go的ParseMAC: http://golang.org/src/net/mac.go?s=866:918#L29 hostname //根據RFC 952 https://tools.ietf.org/html/rfc952驗證字符串值是否為有效主機名 hostname_rfc1123 or if you want to continue to use 'hostname' in your tags, create an alias //根據RFC 1123 https://tools.ietf.org/html/rfc1123驗證字符串值是否為有效主機名 fqdn //這將驗證字符串值是否包含有效的FQDN (完全合格的有效域名),Full Qualified Domain Name (FQDN) html //這將驗證字符串值是否為HTML元素標記,包括https://developer.mozilla.org/en-US/docs/Web/HTML/Element中描述的標記。 html_encoded //這將驗證字符串值是十進制或十六進制格式的正確字符引用 url_encoded //這驗證了根據https://tools.ietf.org/html/rfc3986#section-2.1對字符串值進行了百分比編碼(URL編碼)
dive
例1:
[][]string with validation tag "gt=0,dive,len=1,dive,required" // gt=0 被用於驗證 [] // len=1 被用於驗證 []string // required 被用於驗證 string
例2:
[][]string with validation tag "gt=0,dive,dive,required" // gt=0 被用於驗證 [] // []string 將被保留驗證 // required 被用於驗證 string
Keys & EndKeys
這些將在dive標簽之后直接使用,並告訴驗證者“keys”和“endkeys”之間的任何內容都適用於map的key而不是value;把它想象成'dive'標簽,但是對於map的keys而不是values。
還支持多維嵌套,您希望驗證的每個級別都需要另一個“keys”和“endkeys”標記。這些標簽僅對map有效。
用法:dive,keys,othertagvalidation(s),endkeys,valuevalidationtags
例1:
map[string]string with validation tag "gt=0,dive,keys,eg=1|eq=2,endkeys,required" // gt=0 will be applied to the map itself // eg=1|eq=2 will be applied to the map keys // required will be applied to map values
例2:
map[[2]string]string with validation tag "gt=0,dive,keys,dive,eq=1|eq=2,endkeys,required" // gt=0 will be applied to the map itself // eg=1|eq=2 will be applied to each array element in the the map keys // required will be applied to map values
Field Equals Another Field
這將在結構內或傳入字段中針對另一個字段值驗證字段值。
例1:
// 使用以下方法驗證密碼字段: Usage: eqfield=ConfirmPassword
// 按字段驗證: validate.VarWithValue(password, confirmpassword, "eqfield")
字段等於另一字段(相對)
這與eqfield相同,只是它驗證了相對於頂級結構提供的字段。
Usage: eqcsfield=InnerStructField.Field)
字段不等於另一個字段
這將在結構內或傳入字段中針對另一個字段值驗證字段值。
// 確認兩種顏色不一樣: // 對色域進行驗證: Usage: nefield=Color2 // 按字段驗證: validate.VarWithValue(color1, color2, "nefield")
字段不等於另一個字段(相對)
這與nefield相同,只是它驗證了相對於頂級結構提供的字段。
Usage: necsfield=InnerStructField.Field
字段大於另一字段
僅對Numbers和time.Time類型有效,這將在結構內或傳入字段中針對另一個字段值驗證字段值。用法示例用於驗證開始日期和結束日期:
例1:
// 用於驗證結束字段(對比開始字段): validate.Struct Usage(gtfield=Start)
例2:
// 按字段驗證: validate.VarWithValue(start, end, "gtfield")
字段大於另一個相對字段
這與gtfield相同,不同之處在於它驗證了相對於頂級結構提供的字段。
Usage: gtcsfield=InnerStructField.Field
字段大於或等於另一字段
僅對Numbers和time.Time類型有效,這將在結構內或傳入字段中針對另一個字段值驗證字段值。用法示例用於驗證開始日期和結束日期:
例1:
// 用於驗證結束字段(相對開始字段): validate.Struct Usage(gtefield=Start)
例2:
// 通過字段驗證: validate.VarWithValue(start, end, "gtefield")
字段大於或等於另一個相對字段
這與gtefield相同,只是它驗證了相對於頂級結構提供的字段。
Usage: gtecsfield=InnerStructField.Field
小於另一字段
僅對Numbers和time.Time類型有效,這將在結構內或傳入字段中針對另一個字段值驗證字段值。用法示例用於驗證開始日期和結束日期:
例1:
// Validation on End field using: validate.Struct Usage(ltfield=Start)
例2:
// Validating by field: validate.VarWithValue(start, end, "ltfield")
小於另一相對字段
這與ltfield相同,只是它驗證了相對於頂級結構提供的字段。
Usage: ltcsfield=InnerStructField.Field
小於等於另一字段
僅對Numbers和time.Time類型有效,這將在結構內或傳入字段中針對另一個字段值驗證字段值。用法示例用於驗證開始日期和結束日期:
例1:
// Validation on End field using: validate.Struct Usage(ltefield=Start)
例2:
// Validating by field: validate.VarWithValue(start, end, "ltefield")
小於等於另一相對字段
這與ltefield相同,只是它驗證了相對於頂級結構提供的字段。
Usage: ltecsfield=InnerStructField.Field
======
Alias Validators and Tags(別名驗證器和標簽)
注意:返回error時,“FieldError”中返回的tag將是alias tag,除非dive tag是alias的一部分。dive tag之后的所有內容都不會報告為alias tag。此外,前一種情況中的“ActualTag”將是失敗的alias中的實際tag。 以下是當前內置 alias tag 的列表:
"iscolor" alias is "hexcolor|rgb|rgba|hsl|hsla" (Usage: iscolor)
Validator notes:
regex a regex validator won't be added because commas and = signs can be part of a regex which conflict with the validation definitions. Although workarounds can be made, they take away from using pure regex's. Furthermore it's quick and dirty but the regex's become harder to maintain and are not reusable, so it's as much a programming philosophy as anything. In place of this new validator functions should be created; a regex can be used within the validator function and even be precompiled for better efficiency within regexes.go. And the best reason, you can submit a pull request and we can keep on adding to the validation library of this package!
Panics
This package panics when bad input is provided, this is by design, bad code like that should not make it to production.
type Test struct { TestField string `validate:"nonexistantfunction=1"` } t := &Test{ TestField: "Test" } validate.Struct(t) // this will panic