go-zero 重寫參數驗證器

因爲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
}

post name空

post name 123

get name 空

get name 12345

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章