参数验证功能咨询
ccpwcn opened this issue · 7 comments
Describe the bug
我参照hertz文档写了一段代码,一个小型服务,但是参数验证始终存在问题。下面是我的代码:
package main
import (
"context"
"github.com/cloudwego/hertz/pkg/app/server/binding"
"github.com/cloudwego/hertz/pkg/common/hlog"
"github.com/cloudwego/hertz/pkg/app"
"github.com/cloudwego/hertz/pkg/app/server"
"github.com/cloudwego/hertz/pkg/common/utils"
"github.com/cloudwego/hertz/pkg/protocol/consts"
)
type BindError struct {
ErrType, FailField, Msg string
}
// Error implements error interface.
func (e *BindError) Error() string {
if e.Msg != "" {
return e.ErrType + ": expr_path=" + e.FailField + ", cause=" + e.Msg
}
return e.ErrType + ": expr_path=" + e.FailField + ", cause=invalid"
}
type ValidateError struct {
ErrType, FailField, Msg string
}
// Error implements error interface.
func (e *ValidateError) Error() string {
if e.Msg != "" {
return e.ErrType + ": expr_path=" + e.FailField + ", cause=" + e.Msg
}
return e.ErrType + ": expr_path=" + e.FailField + ", cause=invalid"
}
func init() {
CustomBindErrFunc := func(failField, msg string) error {
err := BindError{
ErrType: "bindErr",
FailField: "[bindFailField]: " + failField,
Msg: "[参数接收失败]: " + msg,
}
return &err
}
CustomValidateErrFunc := func(failField, msg string) error {
err := ValidateError{
ErrType: "validateErr",
FailField: "[validateFailField]: " + failField,
Msg: "[参数验证失败]: " + msg,
}
return &err
}
binding.SetErrorFactory(CustomBindErrFunc, CustomValidateErrFunc)
}
type LoginInput struct {
UserName string `json:"userName,required" vd:"regexp('[a-zA-Z0-9_-]{4,50}$'); msg:'账号格式错误'"`
Password string `json:"password,required"`
Captcha string `json:"captcha,required" vd:"len($)==4; msg:'验证码字符数量不正确'"`
ClientType int `json:"clientType,required" vd:"$==1||$==2||$==3||$==4; msg:'客户端类型无效'"`
}
func main() {
h := server.Default()
h.GET("/ping", func(c context.Context, ctx *app.RequestContext) {
ctx.JSON(consts.StatusOK, utils.H{"msg": "pong"})
})
h.POST("/login", func(c context.Context, ctx *app.RequestContext) {
var req LoginInput
if err := ctx.BindAndValidate(&req); err != nil {
hlog.CtxErrorf(c, "登录参数验证失败:%+v", err)
ctx.JSON(consts.StatusBadRequest, utils.H{"msg": err.Error()})
return
}
hlog.CtxInfof(c, "登录,参数:%+v", req)
ctx.JSON(consts.StatusOK, utils.H{"msg": "login success", "data": req})
})
h.Spin()
}
To Reproduce
- 请求
curl -X POST -d '{"userName":"z","password":"123456","captcha":"1234","clientType":-1}' -H 'Content-Type:application/json' localhost:8888/login
,返回{"msg":"validateErr: expr_path=[validateFailField]: UserName, cause=[参数验证失败]: 账号格式错误"}
这个是符合预期的 - 请求
$ curl -X POST -d '{"userName":"z","password":"123456","captcha":"1234"}' -H 'Content-Type:application/json' localhost:8888/login
,返回{"msg":"bindErr: expr_path=[bindFailField]: clientType, cause=[参数接收失败]: missing required parameter"}
Expected behavior
当我在struct中定义了json的tag和vd之后,vd的校验没问题了,可是json的tag中的required对应的提示消息上哪里去自定义呢?
Hertz version:
v0.4.2
我的gomod
module hertz_demo
go 1.19
require github.com/cloudwego/hertz v0.4.2
require (
github.com/bytedance/go-tagexpr/v2 v2.9.2 // indirect
github.com/bytedance/gopkg v0.0.0-20220413063733-65bf48ffb3a7 // indirect
github.com/bytedance/sonic v1.5.0 // indirect
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06 // indirect
github.com/cloudwego/netpoll v0.3.1 // indirect
github.com/fsnotify/fsnotify v1.5.4 // indirect
github.com/golang/protobuf v1.5.0 // indirect
github.com/henrylee2cn/ameda v1.4.10 // indirect
github.com/henrylee2cn/goutil v0.0.0-20210127050712-89660552f6f8 // indirect
github.com/klauspost/cpuid/v2 v2.0.9 // indirect
github.com/nyaruka/phonenumbers v1.0.55 // indirect
github.com/tidwall/gjson v1.13.0 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.0 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad // indirect
google.golang.org/protobuf v1.27.1 // indirect
)
Environment:
set GO111MODULE=on
set GOARCH=amd64
set GOBIN=
set GOCACHE=C:\Users\lidawei\AppData\Local\go-build
set GOENV=C:\Users\lidawei\AppData\Roaming\go\env
set GOEXE=.exe
set GOEXPERIMENT=
set GOFLAGS=
set GOHOSTARCH=amd64
set GOHOSTOS=windows
set GOINSECURE=
set GOMODCACHE=C:\Users\lidawei\go\pkg\mod
set GONOPROXY=
set GONOSUMDB=
set GOOS=windows
set GOPATH=C:\Users\lidawei\go
set GOPRIVATE=
set GOPROXY=https://goproxy.cn
set GOROOT=C:\Program Files\Go
set GOSUMDB=sum.golang.org
set GOTMPDIR=
set GOTOOLDIR=C:\Program Files\Go\pkg\tool\windows_amd64
set GOVCS=
set GOVERSION=go1.19.2
set GCCGO=gccgo
set GOAMD64=v1
set AR=ar
set CC=gcc
set CXX=g++
set CGO_ENABLED=1
set GOMOD=E:\code\GoglandProjects\hertz_demo\go.mod
set GOWORK=
set CGO_CFLAGS=-g -O2
set CGO_CPPFLAGS=
set CGO_CXXFLAGS=-g -O2
set CGO_FFLAGS=-g -O2
set CGO_LDFLAGS=-g -O2
set PKG_CONFIG=pkg-config
set GOGCCFLAGS=-m64 -mthreads -Wl,--no-gc-sections -fmessage-length=0 -fdebug-prefix-map=C:\Users\lidawei\AppData\Local\Temp\go-build1957160079=/tmp/go-build -gno-record-gcc-switches
PS E:\code\GoglandProjects\hertz_demo>
Additional context
我重点想验证hertz与go-tagexpr整合在一起的时候的强大的参数验证功能,但是认真地讲,文档和资料不太齐全,示例也不够生动,费了好大劲,终于弄明白了基本用法,但是对于required的提示消息,仍然不知道上哪里去自定义。
PATL @FGYFFFF
我看了下 go-tagexpr 的实现,这里其实 required 的校验他在这里直接返回来了一个error。 这应该算是设计的不合理,不过本质上绑定失败的error自定义主要指在反射绑定参数过程发生的。
struct ChangePasswordRequest {
1:required i32 ID (go.tag = 'json:"id"' api.form="id", api.query="id")
2:required string password (api.vd="regexp('^(?=.[a-z])(?=.[A-Z])(?=.\d)(?=.[!@#$%^&*()_-+=]).{8,16}$');msg:'密码至少6个字符,一个小写字母、一个大写字母、一个数字和一个特殊字符'" api.form="password")
}
校验失效,什么原因呀?
@ccpwcn 新提一个 issue 吧,不是一个问题
@ccpwcn 新提一个 issue 吧,不是一个问题
对 go-tagexpr 我已经放弃,不好用。换go-playgroud-v10了
可以的,我也不喜欢用 go-tagexpr
cc @FGYFFFF 民意