当前位置: 首页 > 后端技术 > PHP

【深入理解Go】从0到1实现一个validator

时间:2023-03-30 01:13:32 PHP

Validator是我们日常业务中使用非常广泛的框架组件。集成了很多Web框架和微服务框架。通常用于验证一些请求参数,避免编写重复的验证逻辑。在下一篇文章中,让我们看看如何实现验证器。第一体验实践是第一生产力。我先提供一个场景。现在我们有了一个接口,这个接口是用来填写用户信息的,需要将用户信息保存到数据库中。我们应该怎么做?首先我们定义一个结构体,指定用户信息的几个参数:是传入的,我们需要在入库前进行校验。比如Name是必须的,Email是合法的等等,我们如何实现呢?可以是这样的:funcvalidateEmail(emailstring)error{//dosomethingreturnnil}funcvalidateV1(reqValidateStruct)error{iflen(req.Name)>0{iflen(req.Address)>0{iflen(req.Email)>0{如果错误:=validateEmail(req.Email);err!=nil{returnerr}}else{returnerrors.New("Emailisrequired")}}else{returnerrors.New("Addressisrequired")}}else{returnerrors.New("Nameisrequired")}returnnil}也可以这样:funcvalidateV2(reqValidateStruct)error{iflen(req.Name)<0{returnerrors.New("Nameisrequired")}iflen(req.Address)<0{returnerrors.New("Nameisrequired")}如果len(req.Email)<0||validateEmail(req.Email)!=nil{returnerrors.New("Nameisrequired")}returnnil}可以用可以用,想象一下,如果我们现在要增加100个接口,每个接口都有不同请求参数,这样的逻辑不是要写100遍吗?那是不可能的!我们想办法往前走,我们会发现虽然参数名称不同,但是验证逻辑是可以相同的。比如参数大于0或者小于0,都不等于这个。如果能找到共性,那能不能把共性抽出来呢?逻辑从何而来?让我们先看看我们的一般逻辑。这个方法可以帮助我们验证int和string参数。因为只是为了演示,所以简单实现一下,以表达该方法的可行性。funcvalidateEmail(inputstring)bool{如果通过,_:=regexp.MatchString(`^([\w\.\_]{2,10})@(\w{1,}).([a-z]{2,4})$`,输入,);pass{returntrue}returnfalse}//通用的校园通讯,采用反射现funcvalidate(vinterface{})(bool,string){vt:=reflect.TypeOf(v)vv:=reflect.ValueOf(v)errmsg:="success"validateResult:=truefori:=0;我0,gt=大于Namestring`json:"name"validate:"gt=0"`Addressstring`json:"address"validate:"gt=0"`电子邮件字符串`json:"email"validate:"email;gt=3"`Ageint64`json:"age"validate:"eq=0"`}funcValidateV3(reqValidateStructV3)string{ret,err:=validate(req)if!ret{println(ret,err)returnerr}return""}//实现这个结构体req:=demos.ValidateStructV3{Name:"nosay",Address:"beijing",Email:"nosay@qq.com",Age:3,}resp:=demos.ValidateV3(req)//Output:validateintfailed,tagis:0这样就不需要在每次请求进入业务逻辑之前都写重复的validate()函数,我们也可以将其集成到框架中。原理介绍为上面validator的实现是一样的。它的原理就是下图所示的结构。如果是可确定类型,就会通过标签采取相应的动作。如果是struct,就会递归,继续遍历。struct就是我们的请求体(也就是父节点),子节点对应我们的每一个元素。它的类型是int64、string、struct或其他类型。我们使用类型来执行相应的行为(即int类型的eq=0,string类型的gt=0等)。例如,我们按以下方式运行我们的验证器:typeValidateStructV3struct{//字符串的gt=0表示长度必须>0,gt=大于Namestring`json:"name"validate:"gt=0"`Addressstring`json:"address"validate:"gt=0"`EmailEmailV4Ageint64`json:"age"validate:"eq=0"`}typeEmailV4struct{//gt=字符串0表示长度必须>0,gt=大于Email字符串`json:"email"validate:"email;gt=3"`}req:=demos.ValidateStructV3{Name:"nosay",Address:"beijing",Email:demos.EmailV4{Email:"nosayqq.com",},Age:0,}resp:=demos.ValidateV3(req)这时候它的执行过程是这样的:其实这里已经展开了基本原理说完了,但是真正的实现肯定没有那么简单。在这里,作者推荐一个专门的验证器库(https://github.com/go-playgro...),感兴趣的读者可以阅读~欢迎关注我们,对本系列文章感兴趣的读者订阅我们的公众号,关注博主,下次别迷路了~