因爲go-zer對參數校驗的複雜結構不太好用,因此決定還原使用常規的validate
具體看代碼
package api_utils
import (
"encoding/json"
"errors"
"fmt"
hans "github.com/go-playground/locales/zh"
ut "github.com/go-playground/universal-translator"
"github.com/go-playground/validator/v10"
zh "github.com/go-playground/validator/v10/translations/zh"
"github.com/zeromicro/go-zero/core/logx"
"github.com/zeromicro/go-zero/core/mapping"
"io"
"net/http"
"reflect"
"strings"
)
const (
maxBodyLen = 8 << 20 // 8MB
)
var (
trans ut.Translator //翻譯組件
validate *validator.Validate //校驗組件
formUnmarshaler = mapping.NewUnmarshaler("json", mapping.WithStringValues()) //get參數依舊使用go-zero注入 並且同意的tag 免得總寫錯form json
)
func init() {
validate = validator.New() //初始化
hant := hans.New() //語言包
uni := ut.New(hant, hant) //翻譯組件初始化
trans, _ = uni.GetTranslator("zh")
_ = zh.RegisterDefaultTranslations(validate, trans)
}
func Parse(r *http.Request, v any) error {
var err error
switch r.Method {
// 只用處理一下幾種方法
case http.MethodDelete, http.MethodPut, http.MethodPost:
reader := io.LimitReader(r.Body, maxBodyLen)
err = readBody(reader, v)
case http.MethodGet:
//get 依舊使用uri的方式處理,不改變,其實也可以進行優化
err = r.ParseForm()
if err != nil {
return err
}
params := make(map[string]any, len(r.Form))
for name := range r.Form {
formValue := r.Form.Get(name)
if len(formValue) > 0 {
params[name] = formValue
}
}
if len(params) == 0 {
return errors.New(fmt.Sprintf("request params empty with %s", r.RequestURI))
}
// 使用gozero本身的注入方式就不會有問題(get請求沒有複雜的自定義結構)
err = formUnmarshaler.Unmarshal(params, v)
}
if err != nil {
return err
}
err = validate.Struct(v)
if err != nil {
//翻譯錯誤,這裏是翻譯臺語,讀代碼看了下 自己重寫了trans嘚方法
es := err.(validator.ValidationErrors)
var errStrs = make([]string, len(es))
for i, e := range es {
errStrs[i] = translateFunc(trans, e)
e.Translate(trans)
}
return errors.New("參數錯誤:" + strings.Join(errStrs, " | "))
}
return nil
}
func readBody(reader io.Reader, v interface{}) (err error) {
b, err := io.ReadAll(reader)
if err != nil {
return err
}
return json.Unmarshal(b, v)
}
func translateFunc(ut ut.Translator, fe validator.FieldError) string {
t, err := ut.T(fe.Tag(), fe.Namespace())
if err != nil {
logx.Infof("警告: 翻譯欄位錯誤: %#v", fe)
return fe.(error).Error()
}
return t
}
展示
type HelloReq struct {
Name string `json:"name" validate:"required"`
}
type HelloReq struct {
Name string `json:"name" validate:"required"`
}
func HelloWorld(serverCtx *svc.ServiceContext, ctx context.Context, req interface{}) (interface{}, error) {
r := req.(*HelloReq)
mp := make(map[string]interface{})
mp["name"] = r.Name
return mp, nil
}
func HelloPostWorld(serverCtx *svc.ServiceContext, ctx context.Context, req interface{}) (interface{}, error) {
r := req.(*HelloReq)
mp := make(map[string]interface{})
mp["name"] = r.Name
return mp, nil
}