- Created by 郭强, last modified by 张金富 on May 31, 2023
You are viewing an old version of this page. View the current version.
Compare with Current View Page History
Version 17 Next »
lseRequest
对象支持非常完美的请求校验能力,通过给结构体属性绑定v
标签即可。由于底层校验功能通过gvalid
模块实现,更详细的校验规则和介绍请参考 数据校验-Struct校验 章节。
需要注意的是,从goframe v1.16
版本开始,如果参数采用结构化的输入输出管理,HTTP
请求的数据校验不再受结构体默认值的影响,底层调用的是gvalid
组件的CheckStructWithData
方法,即直接使用请求的参数执行数据校验,而给定的结构体对象仅用于校验规则和错误提示信息的定义管理。
示例1,基本使用
我们将之前的示例做下调整,增加v
校验标签。
package main import ( "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/net/ghttp" ) // RegisterReq 注册请求数据结构 type RegisterReq struct { Name string `p:"username" v:"required|length:4,30#请输入账号|账号长度为:{min}到:{max}位"` Pass string `p:"password1" v:"required|length:6,30#请输入密码|密码长度不够"` Pass2 string `p:"password2" v:"required|length:6,30|same:password1#请确认密码|密码长度不够|两次密码不一致"` } // RegisterRes 注册返回数据结构 type RegisterRes struct { Code int `json:"code"` Error string `json:"error"` Data interface{} `json:"data"` } func main() { s := g.Server() s.Group("/", func(group *ghttp.RouterGroup) { group.ALL("/register", func(r *ghttp.Request) { var req *RegisterReq if err := r.Parse(&req); err != nil { r.Response.WriteJsonExit(RegisterRes{ Code: 1, Error: err.Error(), }) } // ... r.Response.WriteJsonExit(RegisterRes{ Data: req, }) }) }) s.SetPort(8199) s.Run() }
在该示例中,我们定义了两个结构体:RegisterReq
用于参数接收,RegisterRes
用于数据返回。由于该接口返回的是JSON
数据结构,可以看到,只有返回的结构体中存在json
标签,而接收的结构体中只有p
标签。因为RegisterReq
仅用于参数接收,无需设置返回的json
标签。
p
标签是可选的,默认情况下会通过 忽略特殊字符+不区分大小写 的规则进行属性名称匹配转换,默认匹配规则满足绝大部分业务场景。
为了演示测试效果,这里在正常的返回结果Data
属性中将RegisterReq
对象返回,由于该对象没有绑定json
标签,因此返回的JSON
字段将会为其属性名称。
执行后,我们通过curl
工具来测试一下:
$ curl "http://127.0.0.1:8199/register?name=john&password1=123456&password2=123456" {"code":0,"error":"","data":{"Name":"john","Pass":"123456","Pass2":"123456"}} $ curl "http://127.0.0.1:8199/register?name=john&password1=123456&password2=12345" {"code":1,"error":"密码长度不够","data":null} $ curl "http://127.0.0.1:8199/register" {"code":1,"error":"请输入账号","data":null}
示例2,校验错误处理
可以看到在以上示例中,当请求校验错误时,所有校验失败的错误都返回了,这样对于用户体验不是特别友好。当产生错误时,我们可以将校验错误转换为gvalid.Error
接口对象,随后可以通过灵活的方法控制错误的返回。
package main import ( "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/net/ghttp" "github.com/gogf/gf/v2/util/gvalid" ) type RegisterReq struct { Name string `p:"username" v:"required|length:4,30#请输入账号|账号长度为:min到:max位"` Pass string `p:"password1" v:"required|length:6,30#请输入密码|密码长度不够"` Pass2 string `p:"password2" v:"required|length:6,30|same:password1#请确认密码|密码长度不够|两次密码不一致"` } type RegisterRes struct { Code int `json:"code"` Error string `json:"error"` Data interface{} `json:"data"` } func main() { s := g.Server() s.Group("/", func(group *ghttp.RouterGroup) { group.ALL("/register", func(r *ghttp.Request) { var req *RegisterReq if err := r.Parse(&req); err != nil { // Validation error. if v, ok := err.(gvalid.Error); ok { r.Response.WriteJsonExit(RegisterRes{ Code: 1, Error: v.FirstString(), }) } // Other error. r.Response.WriteJsonExit(RegisterRes{ Code: 1, Error: err.Error(), }) } // ... r.Response.WriteJsonExit(RegisterRes{ Data: req, }) }) }) s.SetPort(8199) s.Run() }
可以看到,当错误产生后,我们可以通过err.(gvalid.Error)
断言的方式判断错误是否为校验错误,如果是的话则返回第一条校验错误,而不是所有都返回。更详细的错误控制方法,请参考 数据校验-校验结果 章节。
此外,我们这里也可以使用gerror.Current
获取第一条报错信息,而不是使用断言判断。例如:
var req *RegisterReq if err := r.Parse(&req); err != nil { r.Response.WriteJsonExit(RegisterRes{ Code: 1, Error: gerror.Current(err).Error(), }) }
执行后,我们通过curl
工具来测试一下:
$ curl "http://127.0.0.1:8199/register" {"code":1,"error":"请输入账号","data":null} $ curl "http://127.0.0.1:8199/register?name=john&password1=123456&password2=12345" {"code":1,"error":"两次密码不一致","data":null}
- No labels