如何做好前端頁面異常監控?


在開發工作中難免會出現bug,一般項目都是測試檢查通過后就可以發線上,可是在線上仍舊會出現各種意料之外或者未測試到的問題,這個時候有的用戶會向客服反饋說哪里哪里有問題,這是一種被動的錯誤上報方式,畢竟不是所有的用戶都會上報問題,更多的則是出現問題后直接離開我們的APP。所以異常監控這塊就顯得越來越重要。

頁面異常分類

在我們的項目中我將頁面異常分為以下幾種情況:

  1. javascript異常(語法錯誤,運行時錯誤,跨域腳本)
  2. 資源加載異常(img js css)
  3. ajax請求異常
  4. promise異常
  5. vue項目中全局異常捕獲

接下來介紹如何捕獲這些異常

前端頁面異常捕獲方式

window.onerror捕獲javascript異常

/**
* 捕獲javascript異常
* @param {String}  message    錯誤信息
* @param {String}  source     出錯文件
* @param {Number}  lineno     行號
* @param {Number}  colno      列號
* @param {Object}  error      Error對象(對象)
*/
window.onerror = function (message, source, lineno, colno, error){
    console.log('捕獲到異常:', { message, source, lineno, colno,error });
}

跨域腳本異常捕獲

一般涉及跨域的js運行錯誤時會拋出錯誤提示script error.,但沒有具體信息(如出錯文件,行列號提示等), 可利用資源共享策略來捕獲跨域js錯誤
客戶端:在script標簽增加crossorigin="anonymous"屬性
服務端:靜態資源響應頭Access-Control-Allow-Origin: *

window.addEventListener('error',cb,true)捕獲資源加載異常

img加載異常時會觸發img.onerror函數

// 捕獲資源加載異常
window.addEventListener('error',function(e){
    const err = e.target.src || e.target.href
    if(err){
        console.log('捕獲到資源加載異常',err)
    }
},true)

ajax接口請求異常捕獲

// 統一攔截ajax請求
function ajaxEventTrigger (event) {
    var ajaxEvent = new CustomEvent(event, { detail: this })
    window.dispatchEvent(ajaxEvent)
}

var oldXHR = window.XMLHttpRequest
function newXHR () {
    var realXHR = new oldXHR()
    realXHR.addEventListener('readystatechange', function () { ajaxEventTrigger.call(this, 'ajaxReadyStateChange') }, false)
    return realXHR
}
window.XMLHttpRequest = newXHR
var startTime = 0
var gapTime = 0 // 計算請求延時
window.addEventListener('ajaxReadyStateChange', function (e) {
    var xhr = e.detail
    var status = xhr.status
    var readyState = xhr.readyState
    /**
     * 計算請求延時
     */
    if (readyState === 1) {
        startTime = (new Date()).getTime()
    }
    if (readyState === 4) {
        gapTime = (new Date()).getTime() - startTime
    }
    /**
     * 上報請求信息
     */
     if (readyState === 4) {
        if(status === 200){
            // 接口正常響應時捕獲接口響應耗時
            console.log('接口',xhr.responseURL,'耗時',gapTime)
         }else{
            // 接口異常時捕獲異常接口及狀態碼
            console.log('異常接口',xhr.responseURL,'狀態碼',status)
        }
     }
})

promise異常捕獲

promise 中的報錯順序是:
如果有catch 等捕獲函數,則走catch 捕獲函數。catch 捕獲函數如果沒有拋出新的異常,則下一個then將會認為沒有什么報錯,會繼續執行。
如果沒有catch 等捕獲函數,我們需要注冊 window.addEventListener('unhandledrejection') 來處理

/**
 * Promise catch錯誤上報,需要在使用promise的地方顯示調用.catch(),否則不會捕獲錯誤
 */
if (typeof Promise !== 'undefined') {
    var _promiseCatch = Promise.prototype.catch
    Promise.prototype.catch = function (foo) {
        return _promiseCatch.call(this, catCatch(foo))
    }
}
function catCatch (foo) {
    return function (args) {
        let msg = args.stack ? args.stack : args
        console.log('捕獲到catch中的異常',msg)
        foo && foo.call(this, args)
    }
}

/**
 * 監聽promise未處理的reject錯誤, 跨域情況下監控不到
*/
window.addEventListener('unhandledrejection', event => {
    console.log('捕獲到未處理的promise異常',event.reson)
})

vue項目全局異常捕獲

Vue.config.errorHandler = function (err, vm, info) {
    // `info` 是 Vue 特定的錯誤信息,比如錯誤所在的生命周期鈎子
    // 只在 2.2.0+ 可用
    let msg = `錯誤發生在:${info}中,具體信息:${err.stack}`
    console.log(msg)
}

捕獲到這些異常后我們需要將這些異常上報給服務器,我們直接以請求圖片的形式發送上報內容

異常上報

function report (msg) {
    var reportUrl = 'http://xxxx/report'
    new Image().src = reportUrl + encodeURIComponent(JSON.stringify(msg))
}


免責聲明!

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



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