摘要:一套完善的前端體系應(yīng)少不了異常統(tǒng)計與監(jiān)控,即使有足夠的質(zhì)量保證體系,難免會出現(xiàn)一些意料之外的事,尤其是在復(fù)雜的網(wǎng)路環(huán)境和運行環(huán)境之下。為了保證代碼的健壯性以及頁面的穩(wěn)定性,我們從多個方面來做異常的防范和監(jiān)控。
一套完善的前端體系應(yīng)少不了異常統(tǒng)計與監(jiān)控,即使有足夠的質(zhì)量保證體系,難免會出現(xiàn)一些意料之外的事,尤其是在復(fù)雜的網(wǎng)路環(huán)境和運行環(huán)境之下。為了保證代碼的健壯性以及頁面的穩(wěn)定性,我們從多個方面來做異常的防范和監(jiān)控。
三種思路 主動防御對于我們操作的數(shù)據(jù),尤其是由 API 接口返回的,時常會有一個很復(fù)雜的深層嵌套的數(shù)據(jù)結(jié)構(gòu)。為了代碼的健壯性,很多時候需要對每一層訪問都作空值判斷,就像這樣:
props.user && props.user.posts && props.user.posts[0] && props.user.posts[0].comments && props.user.posts[0].comments[0]
類似的代碼大家可能都寫過,沒寫過大概也見到別人寫過。看起來確實相當(dāng)?shù)夭幻烙^,有句話說得很棒:
The opposite of beautiful is not ugly, but wrong.
我們得找到一種,更簡單、更優(yōu)雅、更安全的方式來處理這種情形。參考這篇文章:Safely Accessing Deeply Nested Values In JavaScript,文章提到借助 Ramda、Lenses、Lodash 以及 Immutable.js 等類庫的方式,并提供一個非常簡潔明了的原生解決方案:
function getIn(p, o) { return p.reduce(function(xs, x) { return (xs && xs[x]) ? xs[x] : null; }, o); }
接下來我們這樣訪問就可以了:
getIn(["user", "posts", 0, "comments"], props)
如果正常訪問到,則返回對應(yīng)的值,否則返回 null。
這里提供的只是主動防御的一種情形,關(guān)于如何編寫更安全的代碼這里不作深入展開。
全局監(jiān)控瀏覽器提供 window.onerror API 來幫助我們進(jìn)行全局的錯誤監(jiān)控:
當(dāng) JavaScript 運行時錯誤(包括語法錯誤)發(fā)生時,會執(zhí)行 window.onerror()`
當(dāng)一項資源(如 或 )加載失敗,能被單一的 window.addEventListener 捕獲
/** * @param {String} message 錯誤信息 * @param {String} source 發(fā)生錯誤的腳本URL * @param {Number} lineno 發(fā)生錯誤的行號 * @param {Number} colno 發(fā)生錯誤的列號 * @param {Object} error Error對象 */ window.onerror = function(message, source, lineno, colno, error) { // ... }
其中 error 對象包含詳細(xì)的錯誤堆棧信息,在 IE9 以前,沒有這個參數(shù)。
針對性捕獲 try..catch可以通過 try..catch 來主動抓取錯誤,想要對一段代碼 try..catch,我們可以這樣:
try { // ... } catch (error) { handler(error) }
對一個函數(shù)做 try..catch 封裝:
function tryify(func) { return function() { try { return func.apply(this, arguments) } catch (error) { handleError(error) throw error } } }為什么是 script error
方案已經(jīng)明確,但還有一些問題。在查看 JavaScript 錯誤統(tǒng)計時,發(fā)現(xiàn) 80% 以上都是 "script error"。原來,當(dāng)加載自不同域的腳本中發(fā)生語法錯誤時,為避免信息泄露,語法錯誤的細(xì)節(jié)將不會報告,而代之簡單的 "Script error."
而在大多數(shù)情況下,我們的靜態(tài)資源放在專門的 CDN 服務(wù)器上,跟站點并不在一個域,所以如果只是簡單的抓取,只會得到一堆意義不大的 script error
解決方案:
添加 CORS 支持
使用 try..catch
添加 CORS 支持需要做兩點:
1.在 script 便簽添加 crossorigin,默認(rèn)值 crossorigin="anonymous"
在 require.js 里提供一個 onNodeCreated hook,供我們提供擴(kuò)展,要添加 crossorigin 屬性,如下所示:
在 2.2.0 版本以上可用(很遺憾的是,目前的集成解決方案版本剛好低于這個版本)。
2.同時在 CDN 服務(wù)器增加響應(yīng)頭 access-control-allow-orgin,配置允許訪問 CORS 的域,否則瀏覽器直接將禁止加載。
try..catch這一點上面也有提到,算是一種比較通用,可定制強(qiáng)的方案。當(dāng)然,在性能上也會有一些損耗。
綜合考慮,try..catch 通用性更好,但由于其在性能方面的一些損耗,CORS 優(yōu)于 try..catch
一個監(jiān)控小工具隨后,介紹一個 JavaScript stack trace 的小工具:https://github.com/CurtisCBS/... ,工具由 Curtis 和 mirreal 共同完成。
主要是用于捕獲頁面 JavaScript 異常報錯,捕獲異常類型包含:
JavaScript runtime 異常捕捉 √
靜態(tài)資源 load faided 異常捕捉 √
console.error 的異常捕獲 √
try..catch 錯誤捕獲 √
使用方式也很簡單,但使用 script mode 引入文件后,調(diào)用 init 函數(shù),進(jìn)行初始化配置和監(jiān)聽
如果是使用 module mode,如下:
// npm install jstracker --save import jstracker from "jstracker" jstracker.init({ concat: false, report: function(errorLogs) { // console.log("send") } })
如果要使用 try..catch 捕獲,jstracker 暴露出一個 tryJS 對象,可以處理 try..catch 包裝,就像這樣:
import jstracker from "jstracker"; this.handleSelect = jstracker.tryJS.wrap(this.handleSelect);
所有錯誤信息統(tǒng)一由 report 函數(shù)處理,可以在此之上做數(shù)據(jù)處理:
// ubt.js import jstracker from "jstracker"; import utility from "utility"; jstracker.init({ concat: false, report: function(errorLogs) { const errorLog = errorLogs[0]; errorLog.ua = window.navigator.userAgent; ubtTracker.send(errorLog); } }); const ubtTracker = { key: { UBT_JS_TRACKER: "xxxx-xxxx-xxxx" }, send(data) { const value = utility.deserializeUrl(data); xxxx.send(["trace", this.key.UBT_JS_TRACKER, value]); } }; function wrapContext(ctx) { for (const func in ctx) { ctx[func] = jstracker.tryJS.wrap(ctx[func]); } } export { wrapContext, ubtTracker, jstracker };概述
作為開發(fā)者以及項目維護(hù)者的身份,我們應(yīng)當(dāng)編寫更安全健壯的代碼。但由于環(huán)境的多樣性,無論再完善的測試,code review 都難免都所疏漏,我們需要一套監(jiān)控系統(tǒng)來完善整個前端體系。
在監(jiān)控的時候,出于同源安全策略無法拿到準(zhǔn)確的錯誤信息,在此,有兩種解決方案:
增加 CORS 支持
使用 try..catch 進(jìn)行異常捕獲
最后,我們對整個監(jiān)控工作封裝了一個基礎(chǔ)的核心,可以監(jiān)控 JavaScript Runtime 異常,資源加載異常,以及 try..catch 捕獲異常等,并給出一個實際工作中的示例。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/83585.html
摘要:前端日報精選新的長度單位你知道么高階函數(shù)一點通的故事隔行掃描算法專題之?dāng)?shù)組去重全家桶每個人都能做的網(wǎng)易云音樂騰訊前端團(tuán)隊社區(qū)中文前端推薦第天聽說你缺少一個順手的圖床知乎專欄譯怎樣創(chuàng)建定制表單組件碎語掘金函數(shù)式編程到底是個啥 2017-06-22 前端日報 精選 CSS 新的長度單位 fr 你知道么?高階函數(shù)一點通png的故事:隔行掃描算法JavaScript專題之?dāng)?shù)組去重 · Issu...
摘要:摘要徒手寫錯誤監(jiān)控。為什么用定時器呢,因為在單頁應(yīng)用中,路由的切換和地址欄的變化是無法被監(jiān)控的,我確實沒有想到特別好的辦法來監(jiān)控,所以用了這種方式,如果有人有更好的辦法,請給我留言,謝謝。 摘要: 徒手寫JS錯誤監(jiān)控。 作者:一步一個腳印一個坑 原文:搭建前端監(jiān)控系統(tǒng)(二)JS錯誤監(jiān)控篇 Fundebug經(jīng)授權(quán)轉(zhuǎn)載,版權(quán)歸原作者所有。 背景:市面上的監(jiān)控系統(tǒng)有很多,大多收費,對于...
摘要:年月,遭到了攻擊,這個事件足以警示我們。自從年雙十一正式上線,累計處理了億錯誤事件,付費客戶有金山軟件百姓網(wǎng)等眾多品牌企業(yè)。 譯者按: 10 年前的博客似乎有點老了,但是XSS 攻擊的威脅依然還在,我們不得不防。 原文: XSS - Stealing Cookies 101 譯者: Fundebug 本文采用意譯,版權(quán)歸原作者所有 竊取Cookie是非常簡單的,因此不要輕易相信...
摘要:譯者按從標(biāo)準(zhǔn),語法以及模塊角度來看,的發(fā)展讓人目不暇接,那么面試題也得與時俱進(jìn)。因此,手動檢查所有依賴是不現(xiàn)實的。為,加之后返回。自從年雙十一正式上線,累計處理了億錯誤事件,得到了金山軟件百姓網(wǎng)等眾多知名用戶的認(rèn)可。 譯者按: 從ECMAScript標(biāo)準(zhǔn),Node.js語法以及NPM模塊角度來看,Node.js的發(fā)展讓人目不暇接,那么面試題也得與時俱進(jìn)。 原文: Node.js In...
閱讀 1714·2021-11-22 15:33
閱讀 2085·2021-10-08 10:04
閱讀 3543·2021-08-27 13:12
閱讀 3419·2019-08-30 13:06
閱讀 1467·2019-08-29 16:43
閱讀 1392·2019-08-29 16:40
閱讀 786·2019-08-29 16:15
閱讀 2746·2019-08-29 14:13