JSON Schema與表單驗證

前端深夜告解室發表於2017-06-26

作者:神機運算元,美團金融前端團隊成員。喜歡簡單,樂於程式設計,富有激情的前端開發者。

表單驗證是一個前端常聊的問題,在這個問題上實際上已經有很多種方案了,大體來說有以下兩種:

  • 自己定義驗證原語,進行簡單封裝,按需定製。這個方案好在對於簡單的小表單上手快,幾經提煉可以形成自己的驗證庫,也可以程式碼保持的精簡。但是出現跨專案複用的時候,容易出現需要補充大量新場景的情況,而且穩定性也不容易保證。
  • 使用市面上已有的表單驗證庫。這個方案能秒殺大部分場景,但可定製性往往比較差,有些驗證庫方案甚至是基於某種元件庫的。另一方面,一旦開始使用某種驗證庫,未來想要切換就非常棘手。

那麼這裡說的方案是否能超越這兩種方案呢?這要從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的表單驗證方案不僅能夠解決我們在表單驗證上的基本需求,同時也在穩定性、可擴充套件性等方面有一定優勢,適合於絕大部分表單驗證的場景。

最後,團隊為了招聘方便,整了個公眾號,主要是一些招聘資訊,團隊資訊,所有的技術文章在公眾號裡也可以看到,對了,如果你想去美團其他團隊,我們也可以幫你內推哦 ~

二維碼
二維碼

相關文章