Go语言通过结构体标签结合validator库实现声明式表单验证:定义含validate标签的结构体,绑定请求数据后调用Validate.Struct()校验,支持多规则、错误翻译与结构化响应,简易场景可手写校验函数。
Go语言本身不内置表单验证框架,但可通过结构体标签(struct tags)结合标准库 reflect 和第三方轻量库(如 go-playground/validator)高效实现声明式、可复用的表单校验逻辑。核心思路是:将HTTP请求数据绑定到结构体,再统一触发验证。
使用 validator 库时,在字段标签中声明校验规则,例如必填、长度、邮箱格式、数值范围等:
go get github.com/go-playground/validator/v10
type UserForm struct {
Username string `json:"username" validate:"required,min=3,max=20,alphanum"`
Email string `json:"email" validate:"required,email"`
Age int `json:"age" validate:"required,gte=0,lte=120"`
Password string `json:"password" validate:"required,min=8"`
}
required 表示非空(对字符串指非空白,对数字指非零值,若需允许零值可用 required_if 或自定义)从 POST 表单或 JSON 请求中读取数据,绑定到结构体后调用验证器:
func createUser(w http.ResponseWriter, r *http.Request) {
var form UserForm
if err := json.NewDecoder(r.Body).Decode(&form); err != nil {
http.Error(w, "无效的JSON", http.StatusBadRequest)
return
}
validate := validator.New()
if err := validate.Struct(form); err != nil {
// 提取所有错误(支持多字段)
for _
, err := range err.(validator.ValidationErrors) {
log.Printf("字段 %s 错误: %s", err.Field(), err.Tag())
}
http.Error(w, "参数校验失败", http.StatusBadRequest)
return
}
// 校验通过,继续业务逻辑...
}
application/x-www-form-urlencoded):
if err := r.ParseForm(); err != nil {
http.Error(w, "解析表单失败", http.StatusBadRequest)
return
}
// 手动赋值或使用 mapstructure + validator 组合
默认错误信息较简略,可通过注册翻译器实现中文提示或上下文感知反馈:
v := validator.New()
trans, _ := en.NewTranslator("en") // 或 zh.NewTranslator("zh")
v.RegisterTranslation("required", trans, func(ut ut.Translator) error {
return ut.Add("required", "{0} 是必填项", true)
}, func(ut ut.Translator, fe validator.FieldError) string {
t, _ := ut.T("required", fe.Field())
return t
})
errors := make(map[string]string)
for _, err := range err.(validator.ValidationErrors) {
errors[err.Field()] = err.Translate(trans)
}
json.NewEncoder(w).Encode(map[string]interface{}{
"success": false,
"errors": errors,
})
对于极简项目,也可手写基础校验函数,避免引入依赖:
func validateUserForm(u UserForm) []string {
var errs []string
if strings.TrimSpace(u.Username) == "" {
errs = append(errs, "用户名不能为空")
} else if len(u.Username) < 3 || len(u.Username) > 20 {
errs = append(errs, "用户名长度需在3-20位之间")
}
if !regexp.MustCompile(`^[a-z0-9._%+\-]+@[a-z0-9.\-]+\.[a-z]{2,}$`).MatchString(u.Email) {
errs = append(errs, "邮箱格式不正确")
}
return errs
}