前端异常监控、上报
在前端代码开发阶段,会有各种各样的bug,通常在上线之前我们会清理掉所有的bug,通过测试之后才上线,但是线上环境也不能保证不会出问题,有些问题可能出现了之后,用户也不会反馈,问题不容易复现,导致不好定位修复,如果有办法在发生异常的时候,自动监控,然后把异常通过接口上报到服务端,这样异常信息就能保留下来,就可以快速定位,修复问题
异常分类
- javascript代码异常(语法错误,执行报错,跨域脚本报错)
- 资源加载异常(img、css、js)
- ajax请求异常
- Promise异常
- Vue项目异常捕获
下面介绍如何捕获这些异常
异常捕获方式
try...catch捕获代码块异常
如果try代码块内的代码存在异常,就会执行catch里面的逻辑,但是无法捕获语法错误和异步代码异常,只能捕获到同步执行报错
try{ console.log(a) }catch(err){ console.log('捕获异常',err) } //捕获异常 ReferenceError: a is not defined at index.html:11
window.onerror全局捕获异常
能捕获同步异步错误,但是不能捕获语法错误和资源错误
/** * 捕获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 }); }
console.log(a)
window.addEventListener('error',cb,true)捕获资源加载异常
window.addEventListener('error',function(e){ const err = e.target.src || e.target.href if(err){ console.log('捕获到资源加载异常',err) } },true) //捕获到资源加载异常 file:///Users/liuxiaoru/Desktop/aa.png
跨域脚本异常捕获
一般涉及跨域的js运行错误时会抛出错误提示script error.,但没有具体信息(如出错文件,行列号提示等), 可利用资源共享策略来捕获跨域js错误
客户端:在script标签增加crossorigin="anonymous"属性
服务端:静态资源响应头Access-Control-Allow-Origin: *
Ajax请求异常
if(status === 200){ // 接口正常响应时捕获接口响应耗时 console.log('接口',xhr.responseURL,'耗时',gapTime) }else{ // 接口异常时捕获异常接口及状态码 console.log('异常接口',xhr.responseURL,'状态码',status) }
promise异常捕获
promise 中的报错顺序是:
如果有catch 等捕获函数,则走catch 捕获函数。catch 捕获函数如果没有抛出新的异常,则下一个then将会认为没有什么报错,会继续执行。
如果没有catch 等捕获函数,我们需要注册 window.addEventListener('unhandledrejection') 来处理
window.addEventListener("unhandledrejection", function(e){ // e.preventDefault(); // 阻止异常向上抛出 console.log('捕获到异常:', e); }); Promise.reject('promise error');
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)) }