阅读 1148

JSON Schema与表单验证

作者:神机算子,美团金融前端团队成员。喜欢简单,乐于编程,富有激情的前端开发者。

表单验证是一个前端常聊的问题,在这个问题上实际上已经有很多种方案了,大体来说有以下两种:

  • 自己定义验证原语,进行简单封装,按需定制。这个方案好在对于简单的小表单上手快,几经提炼可以形成自己的验证库,也可以代码保持的精简。但是出现跨项目复用的时候,容易出现需要补充大量新场景的情况,而且稳定性也不容易保证。
  • 使用市面上已有的表单验证库。这个方案能秒杀大部分场景,但可定制性往往比较差,有些验证库方案甚至是基于某种组件库的。另一方面,一旦开始使用某种验证库,未来想要切换就非常棘手。

那么这里说的方案是否能超越这两种方案呢?这要从JSON Schema本身是什么说起。

JSON Schema是一种用JSON数据来描述需要验证的JSON的格式。利用这种格式,可以做到:

  • 有据可依。每一种验证方式都有固定的写法,即使某一天跨语言,也只需很小的迁移成本。
  • 包罗万象。JSON Schema是一个在不断发展的标准,基本上你想要的验证方法都在里面囊括了。
  • 文本为准。JSON本身只是一段文本,因此这种验证方法无需特别的工具即可编写,也很利于保存和分享。

ajv是JS实现的JSON Schema库。目前来说,它的性能和标准实现覆盖都比较好,具体可以看它项目主页的自我宣传。

在不使用任何验证库、验证工具的情况下,要验证表单需要逐个字段进行读取、判断。表单字段越多,代码的复杂度就越高,而且如果多个表单存在一定的共性,如何复用表单验证也是一个麻烦事。
比如:

图1
图1

单从可读性来说,这段代码非常易读,因为它足够直白、简单,但如果所有的表单验证都这样做,非常容易出错,也不便于维护。

ajv本身只是一个验证工具,这个工具接受一个JSON Schema和你的目标数据,然后返回验证结果。和其他很多验证工具类似,ajv提供了默认的报错文案,默认情况下是英文的。

不过这个无法满足产品对表单验证的需求。理想的表单验证实际上包含以下需求:

  • 对于每个异常的字段,都需要指出其错误
  • 错误需要是产品自己所希望的文案,而不是某种库的内置文案,更别说是英文或者代码中的字段名了
  • 表单验证需要是有序的。直觉上来说,表单验证需要先报页面上最顶端的字段的问题。

对于第一点,ajv完善提供了错误信息。但对于第二点,ajv没有提供比较好的方式来处理,因为它的报错信息是非常程式化的,对于某一类错误,它的文案都是套路。
针对这一点,引入ajv-errors就比较合理了。ajv-errors需要开发在原有的schema中增加一个自定义字段,这个字段对每一种报错都可以定制自己的报错文案,大致如下:

图2
图2

图中errorMessage字段是ajv-errors需要的字段。
这样一来,报错文案的可定制性就非常强了。
那顺序如何保证呢?
一般来说,JSON Schema中如果要验证一个Object的属性,是没有显式顺序的,这个就好像Object在遍历时本身就没有顺序一样。在界面上每个字段的位置,对于JSON Schema来说是透明的,无关的。

幸好ajv的报错是数组形式返回的。尽管数组的顺序在文档中没有明确指出,但这个报错的格式非常友好,它会表明自己是哪个字段。根据这一点,开发只需对报错数组进行一次排序即可,大致如下:

图3
图3

图的顶端指定了字段的顺序,而尾端则使用这个顺序进行了排序。

完美,产品所有的需求都搞定了。

但作为一个合格的前端工程师,我自己是不能就这样收工的。实际上在引入了ajv和ajv-errors之后,前端的JS资源在minify之后膨胀了100KB左右,即使因为gzip能够做到只增加数十KB,这个结果也是不太理想的——太大了。

针对这个情况,如果退一步作为任意项目来对待,那可能我比较想要的做法是将这两个库都进行异步按需加载。这样做的话,多出来的尺寸基本上不会对首次加载造成影响,而且也足够灵活。

但是我们这个项目受限于现有发布系统,没有办法支持webpack的异步按需加载。这怎么搞?

我自己的想法是,将验证挪到node当中去做,让服务器完成这个过程,并将结果返回。

方案是:node端当中内置若干schema,并对每个schema命名,新加一个接口;浏览器端将需要验证的数据和schema的名字发送到node端,并取回验证结果。

从某种角度来说,这也是一种按需加载。粗略来看,这个验证在浏览器端可能会被恶意用户跳过,但只要你提交数据的接口最终没有完善的验证,那其他任何地方所增加的验证都是可以被绕过的,放在浏览器还是node,也就没什么区别了。

从长远来看,这个验证的过程也可以再追加到业务接口上,这样就无法被绕过了。

最后回过头来看,基于JSON Schema的表单验证方案不仅能够解决我们在表单验证上的基本需求,同时也在稳定性、可扩展性等方面有一定优势,适合于绝大部分表单验证的场景。

最后,团队为了招聘方便,整了个公众号,主要是一些招聘信息,团队信息,所有的技术文章在公众号里也可以看到,对了,如果你想去美团其他团队,我们也可以帮你内推哦 ~

二维码
二维码

评论