You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
在 Web 应用中,有一块内容非常重要,却很容易被我们忽略:参数验证,忘了之后常常会给我们造成大量的处理错误问题,甚至直接造成应用崩溃。之前我在 你的团队需要更好的 API 文档流程 提到过,Joi 的验证非常好用,可以帮助我们验证客户端用户的上传数据以及返回数据,而在 Golang 中,我们该如何做呢?
在 Web 应用中,有一块内容非常重要,却很容易被我们忽略:参数验证,忘了之后常常会给我们造成大量的处理错误问题,甚至直接造成应用崩溃。之前我在 你的团队需要更好的 API 文档流程 提到过,Joi 的验证非常好用,可以帮助我们验证客户端用户的上传数据以及返回数据,而在 Golang 中,我们该如何做呢?
如果需要我们自己验证
显然,肯定是有的,而且跟我们又爱又恨的 reflect 有关系,因为对于强类型语言来说,如果没有元编程的帮助,对于数据的验证会变得非常难受:
上面这类似的代码会充斥在你的业务逻辑处理当中,非常不优雅,即使我们可以把常见的验证封装,也不能避免我们这样的情况,充其量只能缩短验证的代码行数而已。
回过头来,当我们有了 reflect 的帮助,验证就会变得非常简单,我们只要在
Struct Tag
中,声明字段的验证要求,剩下的,就交给框架或者中间件去统一处理即可,非常简单而又优雅,并且容易维护。于是,我们今天要介绍的主角就可以出场了:go-playground/validator,它目前最新的版本是 v9,以下内容会跟之前的 v8 版本做一些对比。
字段验证
这是最主要的验证,我们常见的验证就有用户邮箱、非空、最大最小,长度限制等等验证。
其它内容,过于冗长,不方便搬到这里,还是请看文档。
跨字段以及跨 Struct 验证
对于字段之间,甚至跨 Struct 之间的字段验证,它都可以做到,主要有:
eqfield=Field
: 必须等于 Field 的值;nefield=Field
: 必须不等于 Field 的值;gtfield=Field
: 必须大于 Field 的值;gtefield=Field
: 必须大于等于 Field 的值;ltfield=Field
: 必须小于 Field 的值;ltefield=Field
: 必须小于等于 Field 的值;eqcsfield=Other.Field
: 必须等于 struct Other 中 Field 的值;necsfield=Other.Field
: 必须不等于 struct Other 中 Field 的值;gtcsfield=Other.Field
: 必须大于 struct Other 中 Field 的值;gtecsfield=Other.Field
: 必须大于等于 struct Other 中 Field 的值;ltcsfield=Other.Field
: 必须小于 struct Other 中 Field 的值;ltecsfield=Other.Field
: 必须小于等于 struct Other 中 Field 的值;是不是看晕了?没关系,这些 tag 是有规律的,仔细看看就不难发现,他们组成就是 比较符号 + 是否跨 Struct(cross struct) + field,而比较符号就只有 6 种:
eq
: Equal,等于;ne
: Non Equal,不等于;gt
: Great than,大于;gte
: Great than equal,大于等于;lt
: Less than,小于;lte
: Less than equal,小于等于;这样,是不是好记忆一点?
它的用法也是简单明了,直接在后面加上要比较的字段即可:
另外还有几个挺有用的 Tag:
required_with=Field1 Field2
: 在 Field1 或者 Field2 存在时,必须;required_with_all=Field1 Field2
: 在 Field1 与 Field2 都存在时,必须;required_without=Field1 Field2
: 在 Field1 或者 Field2 不存在时,必须;required_without_all=Field1 Field2
: 在 Field1 与 Field2 都存在时,必须;更多还是请看文档。
自定义字段验证
在 v9 之前,validator 的自定义验证一直是这样的:
显得冗长,不优雅,在 v9 经过重新设计以后,我们就可以通过更加优雅的方式来定义自己的字段验证了:
而在我们使用之前,需要注册相应的 Tag:
错误提示
在 v9 之前,我们得到的错误提示非常难看:
这的确能告诉我们哪里出错了,只是,对于使用我们提供的 API 的开发者而言,这种错误就会显得过于生硬而不友好。
于是,v9 提供了对于具体错误的翻译功能。我们可以从例子中看到详细的用法:
经过这样的处理之后,我们可以返回给调用者更加优雅的提示。
与 gin 的配合使用
gin 是使用 validator 非常频繁的 Web 框架,但是它对于升级的 v9,一直保持比较谨慎的态度,因为担心它会对 gin 用户的应用造成一些不兼容的改变,在纠结了将近两年多之后,终于决定在 1.5 的里程碑中发布了。1
不过,其实 validator 的开发者早就给出了 gin 的升级方案,我们可以替换掉
binding
的 validator 即可(这里又体现了 go interface 的设计合理性了:它只是一个抽象,你可以用任何实现去替换它)。而对于错误处理,我们可以写一个中间件去处理,这里需要特别注意的是,
UniversalTranslator
中获得的 Translator 是一个 interface,而它的实例是一个指针,因此我们不能通过重建一个UniversalTranslator
来翻译错误,我们可以将它作为一个参数传入到错误处理逻辑中去:Ref
The text was updated successfully, but these errors were encountered: