數據欄位防衛探索

  • 2019 年 12 月 4 日
  • 筆記

本文作者:IMWeb 黎清龍 原文出處:IMWeb社區 未經同意,禁止轉載

數據欄位防衛探索

這個標題不知道怎麼取,估計沒人看得懂,還是直接看背景吧 -_-!!

背景

某天,小Y借到一個需求:頁面這裡要展示一個列表,cgi數據欄位是xxxlist

太簡單了,幾分鐘的事情:

DB.getData({      // ...      succ: function(data) {          for (var i = 0, l = data.result.xxxlist.length; i < l; ++i) {              showItem(data.result.xxxlist[i]);          }      }  });

自測,免測發布,完美!

但是,沒過多久,客服接到一堆的用戶投訴,xxx頁面打開白屏!

小Y嚇了一跳,怎麼可能,剛剛那個程式碼那麼簡單,絕對不會出錯的!

用用戶投訴的頁面,打開控制台一看:

發現報了一個錯:

排查之後發現,原因是data.result.xxxlist是undefined

頓時一萬匹草泥馬在心裡奔騰而過,不是說好是個列表嗎,沒有列表應該返回[]呀

沒辦法,小Y只能緊急修復程式碼:

DB.getData({      // ...      succ: function(data) {          if (data && data.result && data.result.xxxlist) {              for (var i = 0, l = data.result.xxxlist.length; i < l; ++i) {                  showItem(data.result.xxxlist[i]);              }          }      }  });

分析

上面的背景案例中,小Y忽略了一個很重要的原則:

永遠不要相信輸入!

還記得老師曾經這樣教導我們:

在編寫函數的時候,一定要檢測參數是否合理

對於前端來說,cgi數據也是一樣的,永遠不能相信cgi傳過來的數據!

有人會說,這只是小Y不夠嚴謹,當需要用某些欄位的時候,就應該先檢測

那就又疏忽了,人也是不可信的,當bugfix很緊急的時候還記得嗎?別人寫的程式碼能控制嗎?再細心的人也會有疏忽的時候

另外,如果都加上防衛程式碼的時候,程式碼可能會長成這樣:

DB.getData({      // ...      succ: function(data) {          if (!data) return;          if (!data.a) return;          if (data.b) {              // ...          }            if (data.c) {              // ...          }            if (data.d && data.d.e) {              // ...          }            // 你就一直if下去吧,我不攔你!        }  });

通過背景案例以及分析,現在終於可以解釋數據欄位防衛是什麼東東了

在訪問object.key時,防止object可能是undefined或者null時拋錯

方案

對於這個問題,這裡拋幾個方案,希望可以引出各位讀者的玉!

方案一:抽象cgi數據

類似orm那樣,預先定義model(cgi數據)的schema,如果定義了schema,那我們就可以添加默認值機制了

這個方案的本質就是對cgi數據添加了一層加工層,讓cgi數據變得可信

優點:抽象cgi數據不僅可以做數據欄位防衛,還可以做很多事情 缺點:太重,毫無疑問的

方案二:重定義undefined

比如我們可以這樣:

window.undefined = { length: 0 };

優點:簡單 缺點:某些瀏覽器不支援,見下圖;typeof 會出問題

在瀏覽器不支援的情況下,這個方案可以被槍斃了 -_-!!

方案三:封裝獲取數據欄位的介面

獲取數據欄位不是原生的object.key,而是util.get(object, key),在get方法裡面進行防衛處理

優點:實現統一簡單 缺點:改變了原來的編程習慣;原有程式碼需要改動

方案四:讓工具幫你

讓工具透明的解決這個問題,直接看例子吧

function test(obj) {      var T;      T = require('tools');      var name = T.cookie.get('name');      if (!obj) {          obj = {              count: {                  count: 5              }          };      }      obj.count.count = 6;  }

經過工具之後:

function test(obj) {      var T;      T = require('tools');      T.cookie= T.cookie|| T.cookie=== '' ? T.cookie: {};      var name = T.cookie.get('name');      if (!obj) {          obj = { count: { count: 5 } };      }      obj.count = obj.count || obj.count === '' ? obj.count : {};      obj.count.count = 6;  }

通過工具保證,在訪問object.key之前,object不會是undefined或者是null

優點:透明 缺點:依賴工具的智慧與強大;會添加一些多餘程式碼(因為工具無法識別哪些變數才是真正需要的)

感興趣的話可以看下作者編寫的工具data-member-defender

該工具還需要完善,歡迎提 issue !

Tags: