如何做好前端页面异常监控?
在开发工作中难免会出现bug,一般项目都是测试检查通过后就可以发线上,可是在线上仍旧会出现各种意料之外或者未测试到的问题,这个时候有的用户会向客服反馈说哪里哪里有问题,这是一种被动的错误上报方式,毕竟不是所有的用户都会上报问题,更多的则是出现问题后直接离开我们的APP。所以异常监控这块就显得越来越重要。
页面异常分类
在我们的项目中我将页面异常分为以下几种情况:
- javascript异常(语法错误,运行时错误,跨域脚本)
- 资源加载异常(img js css)
- ajax请求异常
- promise异常
- 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))
}
如果您对本文有什么疑问,欢迎提出个人见解,若您觉得本文对你有用,不妨帮忙点个赞,或者在评论里给我一句赞美,小小成就都是今后继续为大家编写优质文章的动力, 欢迎您持续关注我的博客:)
作者:Jesse131
出处:http://www.cnblogs.com/jesse131/
关于作者:专注前端开发。如有问题或建议,请多多赐教!
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。