防御性編程


文章轉自豆皮范兒——防御性編程

引子

一個測試工程師走進一家酒吧,要了一杯啤酒;

一個測試工程師走進一家酒吧,要了一杯咖啡;

一個測試工程師走進一家酒吧,要了-1杯啤酒;

一個測試工程師走進一家酒吧,要了一份asdfQwer@24dg!&*(@;

一個測試工程師走進一家酒吧,什么也沒要;

一個測試工程師走進一家酒吧,又走出去又進來又出去又進來又出去,最后在外面把老板打了一頓;

一個測試工程師走進一家酒吧,要了NaN杯Null;

一個測試工程師沖進一家酒吧,要了500噸啤酒;

一個測試工程師把酒吧拆了;

一個測試工程師化裝成老板走進一家酒吧,要了500杯啤酒並且不付錢;

一萬個測試工程師在酒吧門外呼嘯而過;

測試工程師們滿意地離開了酒吧。

然后一名顧客點了一份炒飯,酒吧炸了。

今天的主題就是 如何避免酒吧爆炸 防御性編程

防御性編程(Defensive programming)是防御式設計的一種具體體現,它是為了保證,對程序的不可預見的使用,不會造成程序功能上的損壞。 它可以被看作是為了減少或消除墨菲定律效力的想法。

保護我們的代碼遠離來自“外部”的無效數據,無論這個“外部”的概念被定位為什么。

以前端為例,大概包括以下方面

  • 后端接口

  • 字段變化、增減

  • 數據結構變化

  • 各種nullundefined之類的

  • 網絡環境造成的問題

  • 用戶輸入和操作

  • 輸入預期之外的內容

  • 非常規操作,如快速點擊

  • 非常規環境,如慢網速環境

  • 模塊/組件以外的數據
  • ...

防御場景舉例(以JavaScript為例)

空值造成的相關問題


Uncaught TypeError: Cannot read property 'b' of undefined

Uncaught TypeError: fn is not a function

要時刻注意外部變量是否有值,下面是處理空值的幾種方法

  1. 初始化值

// 邏輯或(||)操作符,會在左操作數為 假值 時返回右側操作數。

const newData = data || {}

// 空值合並運算符(??) 是一個邏輯運算符。當左側操作數為 null 或 undefined 時,其返回右側的操作數。否則返回左側的操作數。

const newDataAlt = data ?? {}

console.log(data.id)

  1. 使用 函數默認參數

函數默認參數在沒有值或undefined被傳入時使用默認形參


function divideBy(a, b = 1) {

return a / b;

}

divideBy(10, 2); // 5

divideBy(5); // 5

  • 注意 null或其他falsy值是被認為有值的
  1. 可選鏈操作符?.(Optional chaining)

如果鏈條上的一個引用是nullish (nullundefined),.操作符會引起一個錯誤,?.操作符取而代之的是會按照短路計算的方式返回一個undefined


if (this.props.data && this.props.data.list && this.props.data.list[0]) {

console.log(this.props.data.list[0])

// blabla...

}

// 使用 optional chain

if (this.props.data?.list?.[0]) {

console.log(this.props.data.list[0])

// blabla...

}

異步操作

setTimeout、異步請求等非同步代碼的callback,需要特別注意異步操作前后的狀態變化

  • 要注意dom元素是否一直存在,組件是否unmount,特別是有對canvas的操作的時候

  • 每個異步操作過程中的狀態,頁面上要有相應的loading

  • 初始化的loading

  • 按鈕點擊(防重復點擊)

  • 網絡較差的時候容易暴露loading相關的問題

JSON


Uncaught SyntaxError: Unexpected token } in JSON at position 13

處理json的時候,一般都要使用try catch捕捉錯誤


const json = '{"a":1,"b":2}';

let result;

try {

result = JSON.parse(json);

} catch (e) {

// handle error

}

其他語法錯誤


Uncaught SyntaxError: Invalid or unexpected token

  • 目前項目中均使用eslint,簡單的語法錯誤可以自動提示而避免
  • this.someMethod或者this.state.someState的拼寫錯誤,eslint無法查出來

外部攻擊的防御

XSS

Cross-Site Scripting(跨站腳本攻擊)簡稱 XSS,是一種代碼注入攻擊。攻擊者通過在目標網站上注入惡意腳本,使之在用戶的瀏覽器上運行。利用這些惡意腳本,攻擊者可獲取用戶的敏感信息如 Cookie、SessionID 等,進而危害數據安全。

CSRF

Cross-site request forgery(跨站請求偽造)簡稱CSRF 或者XSRF, 其原理是攻擊者構造網站后台某個功能接口的請求地址,誘導用戶去點擊或者用特殊方法讓該請求地址自動加載。攻擊者盜用了你的身份,以你的名義發送惡意請求。

對防御式編程采取防御的姿態

是不是防御式代碼越多越好呢? No

  • 過度的防御式編程會使程序會變得臃腫而緩慢,增加軟件的復雜度。

要考慮好什么地方需要進行防御,然后因地制宜地調整進行防御式編程的優先級。

  • 通用性防御措施 優於 細節性的防御

例如對於網絡請求,一般是統一處理超時、鑒權、各種錯誤code,而不是在業務層個別處理

  • 根據使用場景,調整防御力度

如項目內部使用的utils函數和公開發布的package,后者防御要求更高

字節跳動數據平台前端團隊,在公司內負責大數據相關產品的研發。我們在前端技術上保持着非常強的熱情,除了數據產品相關的研發外,在數據可視化、海量數據處理優化、web excel、WebIDE、私有化部署、工程工具都方面都有很多的探索和積累,有興趣可以與我們聯系。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM