關于防御性編程
- 你是否遇到過,接口請求失敗或者返回數據錯誤,導致系統白屏
- 或者前端自身寫的代碼存在一些缺陷,導致整個系統不夠健壯,從而導致系統白屏
常見的問題與防范
最常見的問題
- 訪問了null或者undefined的屬性
null.a
Uncaught TypeError: Cannot read properties of null (reading 'a')
- 防御方案:使用可選鏈?.,可選鏈會在遇到空值時返回undefined
const obj = {}
console.log(obj?.a?.b)
前端接口層面的錯誤機制捕獲
使用單例模式,將所有的axios請求都用一個函數封裝一層。統一可以在這個函數中catch捕獲接口調用時候的未知錯誤
單例模式保證一個類只有一個實例,并提供一個全局訪問點來獲取它。
request(config: AxiosRequestConfig) {return new Promise((resolve, reject) => {this.instance.request(config).then(res => {resolve(res)}).catch(err => {reject(err)})})}
前端復雜異步場景導致的錯誤
在前端項目中,直接修改導出的對象會導致狀態不可控,尤其是在復雜異步場景中,你很難判斷數據在某個時刻的值到底是什么、是被誰改的。通過封裝 setter 函數,可以顯式地記錄每次修改的 key 和 value,從而實現「單向數據流」的狀態管理方式。這種方式不僅提升了可讀性與可維護性,還更利于 debug 和擴展,是一種更加穩健的防御性編程策略。
問題背景
// test.js
export const obj = {a: 1,b: 2
}// 使用 obj
import { obj } from './test.js'
obj.a = 3
這段代碼的問題是
- obj是一個導出的全局對象
- 任何文件都能直接修改它的屬性
- 多個模塊、異步任務可能都在讀寫它
- 導致你無法跟蹤它的狀態是怎么變的,在哪變的,什么時候變得
解決方案:
// test.js
export const obj = {a: 1,b: 2
}export function setObj(key, value) {console.log(key, value)obj[key] = value
}
- 修改行為統一管理,數據更可控
- 日志追蹤更方便
擴展
這體現了單向數據流的應用
所有的數據改動都走一個方向,一個入口,不允許亂改
這也是為什么像React、Vue、Redux等框架都鼓勵 “不可變數據 + action” 的方式來改變狀態
前端專注前端
在涉及登錄態、權限控制、敏感信息等安全相關場景中,前端應遵循職責分離的設計理念,盡量避免直接處理或解析敏感數據,僅負責數據的安全轉發和展示控制。鑒權邏輯應統一由后端完成,前端通過接口響應結果進行視圖判斷,從而降低安全風險,提升系統的可維護性與穩定性
頁面做到可降級
對于一些剛上新的業務,或者有存在風險的業務模塊,或者會調取不受信任的接口,例如第三方的接口,這個時候就要做一層降級處理,例如接口調用失敗后,剔除對應模塊的展示,讓用戶無感知的使用
巧用loading和disabled
- 在用戶觸發操作(比如點擊按鈕、提交表單、發起請求)后,及時給按鈕或控件加上 loading 狀態或 disabled 狀態。
- 確保不讓用戶進行重復操作,防止業務側出現 bug
為什么這樣做
- 防止重復提交或者點擊
- 明確交互狀態
- 減輕后端壓力
慎用innerHTML
-
innerHTML 是直接把字符串插入 DOM 的方法;
-
如果插入的字符串中包含 script、<img οnerrοr=…、a href=“javascript:…” 等惡意代碼,瀏覽器就會執行它;
-
這些代碼一旦被執行,可能導致 XSS 攻擊。
什么是XSS攻擊?
- XSS(Cross-Site Scripting)跨站腳本攻擊,是指黑客在頁面中注入惡意腳本代碼,從而獲取用戶信息、劫持登錄態、跳轉釣魚頁面等。
比如:
innerHTML = '<img src="x" onerror="alert(document.cookie)">'
用戶打開這個頁面時就會彈出自己的 cookie,一旦被攻擊者獲取,可能會導致賬戶被盜、信息泄露等嚴重后果。