前端異常監控、上報及js壓縮代碼定位

最近在研究前端異常監控的問題,對查詢的資料作了整理彙總,整體以下html

1、前端異常監控方式

1. window.onerror 異常處理

window.onerror 不管是異步仍是非異步錯誤,onerror 都能捕獲到運行時錯誤。前端

window.onerror = function (msg, url, row, col, error) {
    console.log('我知道錯誤了');
    console.log({
        msg,  url,  row, col, error
    })
    return true;
};
複製代碼

注意:webpack

  • 1)window.onerror 函數只有在返回 true 的時候,異常纔不會向上拋出,不然即便是知道異常的發生控制檯仍是會顯示 Uncaught Error: xxxxx。
  • 2)window.onerror 是沒法捕獲到網絡異常的錯誤。因爲網絡請求異常不會事件冒泡,所以必須在捕獲階段將其捕捉到才行,可是這種方式雖然能夠捕捉到網絡請求的異常,可是沒法判斷 HTTP 的狀態是 404 仍是其餘好比 500 。還須要配合服務端日誌才進行排查分析才能夠。
window.addEventListener('error', (msg, url, row, col, error) => {
    console.log('我知道錯誤了');
    console.log(
        msg, url, row, col, error
    );
    return true;
}, true);
複製代碼

2. Promise錯誤

Promise 實例拋出異常而你沒有用 catch 去捕獲的話,onerror 或 try-catch 也無能爲力,沒法捕捉到錯誤。 若是用到不少 Promise 實例的話,特別是你在一些基於 promise 的異步庫好比 axios 等必定要當心,由於你不知道何時這些異步請求會拋出異常而你並無處理它,因此你最好添加一個 Promise 全局異常捕獲事件 unhandledrejection。ios

window.addEventListener("unhandledrejection", function(e){
    e.preventDefault()
    console.log('我知道 promise 的錯誤了');
    console.log(e.reason);
    return true;
});
複製代碼

3.iframe 錯誤

父窗口直接使用 window.onerror 是沒法直接捕獲,若是你想要捕獲 iframe 的異常的話,有分好幾種狀況。git

1) 若是你的 iframe 頁面和你的主站是同域名的話,直接給 iframe 添加 onerror 事件便可。

<iframe src="./iframe.html" frameborder="0"></iframe>
<script>
  window.frames[0].onerror = function (msg, url, row, col, error) {
    console.log('我知道 iframe 的錯誤了,也知道錯誤信息');
    console.log({
      msg,  url,  row, col, error
    })
    return true;
  };
</script>
複製代碼

2)若是你嵌入的 iframe 頁面和你的主站不是同個域名的,可是 iframe 內容不屬於第三方

能夠經過與 iframe 通訊的方式將異常信息拋給主站接收。與 iframe 通訊的方式有不少,經常使用的如: postMessage,hash 或者 name字段跨域等等github

3)若是是非同域且網站不受本身控制的話,除了經過控制檯看到詳細的錯誤信息外,沒辦法捕獲

2、監控上報

監控拿到報錯信息以後,接下來就須要將捕捉到的錯誤信息發送到信息收集平臺上,經常使用的發送形式主要有兩種:web

  • 經過 Ajax 發送數據
  • 動態建立 img 標籤的形式
function error(msg,url,line){
   var REPORT_URL = "xxxx/cgi"; // 收集上報數據的信息
   var m =[msg, url, line, navigator.userAgent, +new Date];// 收集錯誤信息,發生錯誤的腳本文件網絡地址,用戶代理信息,時間
   var url = REPORT_URL + m.join('||');// 組裝錯誤上報信息內容URL
   var img = new Image;
   img.onload = img.onerror = function(){
      img = null;
   };
   img.src = url;// 發送數據到後臺cgi
}
// 監聽錯誤上報
window.onerror = function(msg,url,line){
   error(msg,url,line);
}
複製代碼

3、JS代碼壓縮後,如何定位

該部分原文出處:https://github.com/joeyguo/blog/issues/14axios

示例:跨域

1.源代碼(存在錯誤)

function test() {
    noerror // <- 報錯
}

test();
複製代碼

2.經 webpack 打包壓縮後產生以下代碼

!function(n){function r(e){if(t[e])return t[e].exports;var o=t[e]={i:e,l:!1,exports:{}};return n[e].call(o.exports,o,o.exports,r),o.l=!0,o.exports}var t={};r.m=n,r.c=t,r.i=function(n){return n},r.d=function(n,t,e){r.o(n,t)||Object.defineProperty(n,t,{configurable:!1,enumerable:!0,get:e})},r.n=function(n){var t=n&&n.__esModule?function(){return n.default}:function(){return n};return r.d(t,"a",t),t},r.o=function(n,r){return Object.prototype.hasOwnProperty.call(n,r)},r.p="",r(r.s=0)}([function(n,r){function t(){noerror}t()}]);
複製代碼

3.代碼如期報錯,並上報相關信息

{ msg: 'Uncaught ReferenceError: noerror is not defined',
  url: 'http://127.0.0.1:8077/main.min.js',
  row: '1',
  col: '515' }
複製代碼

此時,錯誤信息中行列數爲 1 和 515。 結合壓縮後的代碼,肉眼觀察很難定位出具體問題。promise

方案一:將壓縮代碼中分號變成換行

uglifyjs 有一個叫 semicolons 配置參數,設置爲 false 時,會將壓縮代碼中的分號替換爲換行符,提升代碼可讀性, 如

!function(n){function r(e){if(t[e])return t[e].exports
var o=t[e]={i:e,l:!1,exports:{}}
return n[e].call(o.exports,o,o.exports,r),o.l=!0,o.exports}var t={}
r.m=n,r.c=t,r.i=function(n){return n},r.d=function(n,t,e){r.o(n,t)||Object.defineProperty(n,t,{configurable:!1,enumerable:!0,get:e})},r.n=function(n){var t=n&&n.__esModule?function(){return n.default}:function(){return n}
return r.d(t,"a",t),t},r.o=function(n,r){return Object.prototype.hasOwnProperty.call(n,r)},r.p="",r(r.s=0)}([function(n,r){function t(){noerror}t()}])
複製代碼

此時,錯誤信息中行列數爲 5 和 137,查找起來比普通壓縮方便很多。但仍會出現一行中有不少代碼,不容易定位的問題。

方案二:js 代碼半壓縮 · 保留空格和換行

uglifyjs 的另外一配置參數 beautify 設置爲 true 時,最終代碼將呈現壓縮後進行格式化的效果(保留空格和換行),如

!function(n) {
    // ...
    // ...
}([ function(n, r) {
    function t() {
        noerror;
    }
    t();
} ]);
複製代碼

此時,錯誤信息中行列數爲 32 和 9,可以快速定位到具體位置,進而對應到源代碼。但因爲增長了換行和空格,因此文件大小有所增長。

方案三:SourceMap 快速定位

SourceMap 是一個信息文件,存儲着源文件的信息及源文件與處理後文件的映射關係。 在定位壓縮代碼的報錯時,能夠經過錯誤信息的行列數與對應的 SourceMap 文件,處理後獲得源文件的具體錯誤信息。

SourceMap 文件中的 sourcesContent 字段對應源代碼內容,不但願將 SourceMap 文件發佈到外網上,而是將其存儲到腳本錯誤處理平臺上,只用在處理腳本錯誤中。 經過 SourceMap 文件能夠獲得源文件的具體錯誤信息,結合 sourcesContent 上源文件的內容進行可視化展現,讓報錯信息一目瞭然!

sourceMap

方案四:開源方案 sentry

sentry 是一個實時的錯誤日誌追蹤和聚合平臺,包含了上面 sourcemap 方案,並支持更多功能,如:錯誤調用棧,log 信息,issue管理,多項目,多用戶,提供多種語言客戶端等,具體介紹能夠查看 getsentry/sentry,sentry.io,這裏暫不展開。

sentry

參考文章:

  1. 跨域,你須要知道的全在這裏
  2. 腳本錯誤量極致優化-讓腳本錯誤一目瞭然
  3. 前端代碼異常監控實戰
相關文章
相關標籤/搜索