Go (Golang) 数据验证:工具、示例与最佳实践
数据验证是任何 Web 应用或 API 开发的关键环节之一。在 Go (Golang) 中,由于强类型、强大的库和内置功能,这一任务可以非常优雅地完成。本文将介绍数据校验的主要方法、流行库,并提供实用的代码示例。
为什么 Go 需要验证?
Go 编译为原生代码,不像 Python 或 JavaScript 那样拥有内置的反射系统。然而,开发者创建了几个优秀的库,可以实现:
- 检查结构体字段是否符合格式(email、URL、电话);
- 设置限制条件(min、max、required);
- 为业务逻辑创建自定义验证器;
- 与 Web 框架(Gin、Echo、Fiber)集成。
1. go-playground/validator 库(最流行)
go-playground/validator 是 Go 中结构体验证的事实标准。它使用结构体字段中的标签(tags),并支持超过 100 个内置规则。
package main
import ( "fmt" "github.com/go-playground/validator/v10")
type User struct { Name string `validate:"required,min=2,max=50"` Email string `validate:"required,email"` Age int `validate:"gte=18,lte=120"`}
func main() { validate := validator.New() user := User{ Name: "A", Email: "invalid-email", Age: 15, } err := validate.Struct(user) if err != nil { for _, e := range err.(validator.ValidationErrors) { fmt.Printf("字段: %s, 错误: %s, 值: %v", e.Field(), e.Tag(), e.Value()) } }}输出:
字段: Name, 错误: min, 值: A字段: Email, 错误: email, 值: invalid-email字段: Age, 错误: gte, 值: 152. ozzo-validation 库(支持链式调用的替代方案)
ozzo-validation 提供了一种更声明式的风格,无需使用标签。适用于无法修改结构体或需要动态验证的场景。
package main
import ( "fmt" "github.com/go-ozzo/ozzo-validation/v4" "github.com/go-ozzo/ozzo-validation/v4/is")
type Product struct { Name string Price float64}
func main() { p := Product{Name: "", Price: -10} err := validation.ValidateStruct(&p, validation.Field(&p.Name, validation.Required, validation.Length(1, 100)), validation.Field(&p.Price, validation.Required, validation.Min(0.01)), ) if err != nil { fmt.Println(err) }}3. 自定义验证器
有时需要内置规则未提供的检查。例如,密码验证或名称唯一性验证。
package main
import ( "fmt" "github.com/go-playground/validator/v10" "unicode")
func passwordValidator(fl validator.FieldLevel) bool { pwd := fl.Field().String() hasUpper := false hasDigit := false for _, ch := range pwd { if unicode.IsUpper(ch) { hasUpper = true } if unicode.IsDigit(ch) { hasDigit = true } } return len(pwd) >= 8 && hasUpper && hasDigit}
type Account struct { Password string `validate:"password"`}
func main() { validate := validator.New() validate.RegisterValidation("password", passwordValidator)
acc := Account{Password: "weak"} err := validate.Struct(acc) if err != nil { fmt.Println("密码未通过验证") } else { fmt.Println("密码正确") }}4. 使用 Gin 验证 HTTP 请求
Gin 框架使用