自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

一篇文章教你如何捕獲前端錯(cuò)誤

新聞 前端
隨著前端頁面承載功能越來越多,用戶本地瀏覽器環(huán)境也錯(cuò)綜復(fù)雜,因此即使有完善的測試,我們也無法保證上線的代碼不會(huì)出錯(cuò)。

隨著前端頁面承載功能越來越多,用戶本地瀏覽器環(huán)境也錯(cuò)綜復(fù)雜,因此即使有完善的測試,我們也無法保證上線的代碼不會(huì)出錯(cuò)。在這種場景下,前端頁面的監(jiān)控就成了各個(gè)web項(xiàng)目必備的工具。

 

一般對(duì)頁面的監(jiān)控包含頁面性能、頁面錯(cuò)誤以及用戶行為路徑獲取上報(bào)等。

 

而本文將重點(diǎn)關(guān)注其中的錯(cuò)誤部分,主要介紹一下常見的錯(cuò)誤類型以及如何對(duì)它們進(jìn)行捕獲并上報(bào)。

常見錯(cuò)誤的分類

對(duì)于用戶在訪問頁面時(shí)發(fā)生的錯(cuò)誤,主要包括以下幾個(gè)類型:

1、js運(yùn)行時(shí)錯(cuò)誤

JavaScript代碼在用戶瀏覽器中執(zhí)行時(shí),由于一些邊界情況、本地環(huán)境的不可控等因素,可能會(huì)存在js運(yùn)行時(shí)錯(cuò)誤。

而依賴客戶端的某些方法,由于兼容性或者網(wǎng)絡(luò)等問題,也有概率會(huì)出現(xiàn)運(yùn)行時(shí)錯(cuò)誤。

e.g: 下圖是當(dāng)使用了未定義的變量"foo",導(dǎo)致產(chǎn)生js運(yùn)行時(shí)錯(cuò)誤時(shí)的上報(bào)數(shù)據(jù):

 

2、資源加載錯(cuò)誤

這里的靜態(tài)資源包括js、css以及image等。現(xiàn)在的web項(xiàng)目,往往依賴了大量的靜態(tài)資源,而且一般也會(huì)有cdn存在。

如果某個(gè)節(jié)點(diǎn)出現(xiàn)問題導(dǎo)致某個(gè)靜態(tài)資源無法訪問,就需要能夠捕獲這種異常并進(jìn)行上報(bào),方便***時(shí)間解決問題。

e.g: 下圖是圖片資源不存在時(shí)的上報(bào)數(shù)據(jù):

3、未處理的promise錯(cuò)誤

未使用catch捕獲的promise錯(cuò)誤,往往都會(huì)存在比較大的風(fēng)險(xiǎn)。而編碼時(shí)有可能覆蓋的不夠全面,因此有必要監(jiān)控未處理的promise錯(cuò)誤并進(jìn)行上報(bào)。

e.g: 下圖是promise請(qǐng)求接口發(fā)生錯(cuò)誤后,未進(jìn)行catch時(shí)的上報(bào)數(shù)據(jù):

4、異步請(qǐng)求錯(cuò)誤(fetch與xhr)

異步錯(cuò)誤的捕獲分為兩個(gè)部分:一個(gè)是傳統(tǒng)的XMLHttpRequest,另一個(gè)是使用fetch api。

像axios和jQuery等庫就是在xhr上的封裝,而有些情況也可能會(huì)使用原生的fetch,因此對(duì)這兩種情況都要進(jìn)行捕獲。

e.g: 下圖是xhr請(qǐng)求接口返回400時(shí)捕獲后的上報(bào)數(shù)據(jù):

 

各個(gè)類型錯(cuò)誤的捕獲方式

1、window.onerror與window.addEventListener('error')捕獲js運(yùn)行時(shí)錯(cuò)誤

使用window.onerror和window.addEventListener('error')都能捕獲,但是window.onerror含有詳細(xì)的error堆棧信息,存在error.stack中,所以我們選擇使用onerror的方式對(duì)js運(yùn)行時(shí)錯(cuò)誤進(jìn)行捕獲。

  1. window.onerror = function (msg, url, lineNo, columnNo, error) { 
  2.     // 處理錯(cuò)誤信息 
  3. // demo 
  4. msg: Uncaught TypeError: Uncaught ReferenceError: a is not defined 
  5. error.statck: TypeError: ReferenceError: a is not defined at http://xxxx.js:1:13 
  6. window.addEventListener('error', event => (){  
  7.   // 處理錯(cuò)誤信息 
  8. }, false); 
  9. // true代表在捕獲階段調(diào)用,false代表在冒泡階段捕獲。使用true或false都可以,默認(rèn)為false 

2、資源加載錯(cuò)誤使用addEventListener去監(jiān)聽error事件捕獲

實(shí)現(xiàn)原理:當(dāng)一項(xiàng)資源(如<img>或<script>)加載失敗,加載資源的元素會(huì)觸發(fā)一個(gè)Event接口的error事件,并執(zhí)行該元素上的onerror()處理函數(shù)。

這些error事件不會(huì)向上冒泡到window,不過能被window.addEventListener在捕獲階段捕獲。

但這里需要注意,由于上面提到了addEventListener也能夠捕獲js錯(cuò)誤,因此需要過濾避免重復(fù)上報(bào),判斷為資源錯(cuò)誤的時(shí)候才進(jìn)行上報(bào)。

  1. window.addEventListener('error', event => (){  
  2.   // 過濾js error 
  3.   let target = event.target || event.srcElement; 
  4.   let isElementTarget = target instanceof HTMLScriptElement || target instanceof HTMLLinkElement || target instanceof HTMLImageElement; 
  5.   if (!isElementTarget) return false
  6.   // 上報(bào)資源地址 
  7.   let url = target.src || target.href; 
  8.   console.log(url); 
  9. }, true); 

3、未處理的promise錯(cuò)誤處理方式

實(shí)現(xiàn)原理:當(dāng)promise被reject并且錯(cuò)誤信息沒有被處理的時(shí)候,會(huì)拋出一個(gè)unhandledrejection。

這個(gè)錯(cuò)誤不會(huì)被window.onerror以及window.addEventListener('error')捕獲,但是有專門的window.addEventListener('unhandledrejection')方法進(jìn)行捕獲處理。

  1. window.addEventListener('rejectionhandled', event => { 
  2.   // 錯(cuò)誤的詳細(xì)信息在reason字段 
  3.   // demo:settimeout error 
  4.   console.log(event.reason); 
  5. }); 

4、fetch與xhr錯(cuò)誤的捕獲

對(duì)于fetch和xhr,我們需要通過改寫它們的原生方法,在觸發(fā)錯(cuò)誤時(shí)進(jìn)行自動(dòng)化的捕獲和上報(bào)。

改寫fetch方法:

  1. // fetch的處理 
  2. function _errorFetchInit () { 
  3.     if(!window.fetch) return
  4.     let _oldFetch = window.fetch; 
  5.     window.fetch = function () { 
  6.         return _oldFetch.apply(this, arguments) 
  7.         .then(res => { 
  8.             if (!res.ok) { // 當(dāng)status不為2XX的時(shí)候,上報(bào)錯(cuò)誤 
  9.             } 
  10.             return res; 
  11.         }) 
  12.         // 當(dāng)fetch方法錯(cuò)誤時(shí)上報(bào) 
  13.         .catch(error => { 
  14.             // error.message, 
  15.             // error.stack 
  16.             // 拋出錯(cuò)誤并且上報(bào) 
  17.             throw error;  
  18.         }) 
  19.     } 

對(duì)于XMLHttpRequest的重寫:

xhr改寫

  1. // xhr的處理 
  2. function _errorAjaxInit () { 
  3.     let protocol = window.location.protocol; 
  4.     if (protocol === 'file:'return
  5.     // 處理XMLHttpRequest 
  6.     if (!window.XMLHttpRequest) { 
  7.         return;   
  8.     } 
  9.     let xmlhttp = window.XMLHttpRequest;     
  10.     // 保存原生send方法 
  11.     let _oldSend = xmlhttp.prototype.send; 
  12.     let _handleEvent = function (event) { 
  13.         try { 
  14.             if (event && event.currentTarget && event.currentTarget.status !== 200) { 
  15.                     // event.currentTarget 即為構(gòu)建的xhr實(shí)例 
  16.                     // event.currentTarget.response 
  17.                     // event.currentTarget.responseURL || event.currentTarget.ajaxUrl 
  18.                     // event.currentTarget.status 
  19.                     // event.currentTarget.statusText 
  20.                 }); 
  21.             } 
  22.         } catch (e) {va 
  23.             console.log('Tool\'s error: ' + e); 
  24.         } 
  25.     } 
  26.     xmlhttp.prototype.send = function () { 
  27.         this.addEventListener('error', _handleEvent); // 失敗 
  28.         this.addEventListener('load', _handleEvent);  // 完成 
  29.         this.addEventListener('abort', _handleEvent); // 取消 
  30.         return _oldSend.apply(this, arguments); 
  31.     } 

關(guān)于responseURL 的說明

需要特別注意的是,當(dāng)請(qǐng)求完全無法執(zhí)行的時(shí)候,XMLHttpRequest會(huì)收到status=0 和 statusText=null的返回,此時(shí)responseURL也為空string。

另外在安卓4.4及以下版本的webview中,xhr對(duì)象也不存在responseURL屬性。

因此我們需要額外的改寫xhr的open方法,將傳入的url記錄下來,方便上報(bào)時(shí)帶上。

  1. var _oldOpen = xmlhttp.prototype.open; 
  2. // 重寫open方法,記錄請(qǐng)求的url 
  3. xmlhttp.prototype.open = function (method, url) { 
  4.     _oldOpen.apply(this, arguments); 
  5.     this.ajaxUrl = url; 
  6. }; 

其他問題

1、其他框架,例如vue項(xiàng)目的錯(cuò)誤捕獲

vue內(nèi)部發(fā)生的錯(cuò)誤會(huì)被Vue攔截,因此vue提供方法給我們處理vue組件內(nèi)部發(fā)生的錯(cuò)誤。

  1. Vue.config.errorHandler = function (err, vm, info) {  // handle error  // `info` 是 Vue 特定的錯(cuò)誤信息,比如錯(cuò)誤所在的生命周期鉤子  // 只在 2.2.0+ 可用} 

2、script error的解決方式

"script error.”有時(shí)也被稱為跨域錯(cuò)誤。當(dāng)網(wǎng)站請(qǐng)求并執(zhí)行一個(gè)托管在第三方域名下的腳本時(shí),就可能遇到該錯(cuò)誤。最常見的情形是使用 CDN 托管 JS 資源。

其實(shí)這并不是一個(gè) JavaScript Bug。出于安全考慮,瀏覽器會(huì)刻意隱藏其他域的 JS 文件拋出的具體錯(cuò)誤信息,這樣做可以有效避免敏感信息無意中被不受控制的第三方腳本捕獲。

因此,瀏覽器只允許同域下的腳本捕獲具體錯(cuò)誤信息,而其他腳本只知道發(fā)生了一個(gè)錯(cuò)誤,但無法獲知錯(cuò)誤的具體內(nèi)容。

解決方案1:(推薦)

添加 crossorigin="anonymous" 屬性。

  1. <script src="http://another-domain.com/app.js" crossorigin="anonymous"></script> 

此步驟的作用是告知瀏覽器以匿名方式獲取目標(biāo)腳本。這意味著請(qǐng)求腳本時(shí)不會(huì)向服務(wù)端發(fā)送潛在的用戶身份信息(例如 Cookies、HTTP 證書等)。

添加跨域 HTTP 響應(yīng)頭:

  1. Access-Control-Allow-Origin: * 

或者

  1. Access-Control-Allow-Origin: http://test.com 

注意:大部分主流 CDN 默認(rèn)添加了 Access-Control-Allow-Origin 屬性。

完成上述兩步之后,即可通過 window.onerror 捕獲跨域腳本的報(bào)錯(cuò)信息。

解決方案2

難以在 HTTP 請(qǐng)求響應(yīng)頭中添加跨域?qū)傩詴r(shí),還可以考慮 try catch 這個(gè)備選方案。

在如下示例 HTML 頁面中加入 try catch:

  1. <!doctype html> 
  2. <html> 
  3. <head> 
  4.     <title>Test page in http://test.com</title> 
  5. </head> 
  6. <body> 
  7.     <script src="http://another-domain.com/app.js"></script> 
  8.     // app.js里面有一個(gè)foo方法,調(diào)用了不存在的bar方法 
  9.     <script> 
  10.     window.onerror = function (message, url, line, column, error) { 
  11.         console.log(message, url, line, column, error); 
  12.     } 
  13.     try { 
  14.         foo(); 
  15.     } catch (e) { 
  16.         console.log(e); 
  17.  
  18.         throw e; 
  19.     } 
  20. </script> 
  21. </body> 
  22. </html> 
  23.  
  24. // 運(yùn)行輸出結(jié)果如下: 
  25.  
  26. => ReferenceError: bar is not defined 
  27. at foo (http://another-domain.com/app.js:2:3) 
  28. at http://test.com/:15:3 
  29. => "Script error."""00, undefined 

可見 try catch 中的 Console 語句輸出了完整的信息,但 window.onerror 中只能捕獲“Script error”。根據(jù)這個(gè)特點(diǎn),可以在 catch 語句中手動(dòng)上報(bào)捕獲的異常。

總結(jié)

上述的錯(cuò)誤捕獲基本覆蓋了前端監(jiān)控所需的錯(cuò)誤場景,但是第三部分指出的兩個(gè)其他問題,目前解決的方式都不太***。

對(duì)于有使用框架的項(xiàng)目:一是需要有額外的處理流程,比如示例中就需要單獨(dú)為vue項(xiàng)目進(jìn)行初始化;二是對(duì)于其他框架,都需要單獨(dú)處理,例如react項(xiàng)目的話,則需要使用官方提供的componentDidCatch方法來做錯(cuò)誤捕獲。

而對(duì)于跨域js捕獲的問題:我們并不能保證所有的跨域靜態(tài)資源都添加跨域 HTTP 響應(yīng)頭;而通過第二種包裹try-catch的方式進(jìn)行上報(bào),則需要考慮的場景繁多并且無法保證沒有遺漏。

雖然存在這兩點(diǎn)不足,但前端錯(cuò)誤捕獲這部分還是和項(xiàng)目的使用場景密切相關(guān)的。我們可以在了解這些方式以后,選擇最適合自己項(xiàng)目的方案,為自己的監(jiān)控工具服務(wù)。

責(zé)任編輯:張燕妮 來源: vivo互聯(lián)網(wǎng)技術(shù)
相關(guān)推薦

2022-10-08 15:07:06

ChatOps運(yùn)維

2017-09-05 08:52:37

Git程序員命令

2021-03-08 09:15:46

日志Filebeat運(yùn)維

2020-03-31 08:37:31

遞歸單鏈表反轉(zhuǎn)

2020-10-09 08:15:11

JsBridge

2021-05-11 10:01:54

avaScript錯(cuò)誤處理

2018-01-09 05:39:02

2022-02-21 09:44:45

Git開源分布式

2023-05-12 08:19:12

Netty程序框架

2021-06-30 00:20:12

Hangfire.NET平臺(tái)

2019-04-17 15:16:00

Sparkshuffle算法

2021-04-09 08:40:51

網(wǎng)絡(luò)保險(xiǎn)網(wǎng)絡(luò)安全網(wǎng)絡(luò)風(fēng)險(xiǎn)

2024-06-25 08:18:55

2021-09-05 17:22:08

Strview.js工具js

2023-04-13 08:21:38

DevOpsAPI管理平臺(tái)

2021-11-04 10:34:02

JavaScript繼承編程

2019-11-14 15:44:32

系統(tǒng)緩存架構(gòu)

2022-02-18 00:13:53

JavaScript編程語言數(shù)組

2013-04-15 10:59:08

iOS開發(fā)ARC版本說明

2022-12-14 08:03:27

CSS變量前端
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)