最近在研究前端异常监控的问题,对查询的资料作了整理汇总,整体以下html
window.onerror 不管是异步仍是非异步错误,onerror 都能捕获到运行时错误。前端
window.onerror = function (msg, url, row, col, error) {
console.log('我知道错误了');
console.log({
msg, url, row, col, error
})
return true;
};
复制代码
注意:webpack
window.addEventListener('error', (msg, url, row, col, error) => {
console.log('我知道错误了');
console.log(
msg, url, row, col, error
);
return true;
}, true);
复制代码
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;
});
复制代码
父窗口直接使用 window.onerror 是没法直接捕获,若是你想要捕获 iframe 的异常的话,有分好几种状况。git
<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>
复制代码
能够经过与 iframe 通讯的方式将异常信息抛给主站接收。与 iframe 通讯的方式有不少,经常使用的如: postMessage,hash 或者 name字段跨域等等github
监控拿到报错信息以后,接下来就须要将捕捉到的错误信息发送到信息收集平台上,经常使用的发送形式主要有两种:web
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);
}
复制代码
该部分原文出处:https://github.com/joeyguo/blog/issues/14axios
示例:跨域
function test() {
noerror // <- 报错
}
test();
复制代码
!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()}]);
复制代码
{ 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,查找起来比普通压缩方便很多。但仍会出现一行中有不少代码,不容易定位的问题。
uglifyjs 的另外一配置参数 beautify 设置为 true 时,最终代码将呈现压缩后进行格式化的效果(保留空格和换行),如
!function(n) {
// ...
// ...
}([ function(n, r) {
function t() {
noerror;
}
t();
} ]);
复制代码
此时,错误信息中行列数为 32 和 9,可以快速定位到具体位置,进而对应到源代码。但因为增长了换行和空格,因此文件大小有所增长。
SourceMap 是一个信息文件,存储着源文件的信息及源文件与处理后文件的映射关系。 在定位压缩代码的报错时,能够经过错误信息的行列数与对应的 SourceMap 文件,处理后获得源文件的具体错误信息。
SourceMap 文件中的 sourcesContent 字段对应源代码内容,不但愿将 SourceMap 文件发布到外网上,而是将其存储到脚本错误处理平台上,只用在处理脚本错误中。 经过 SourceMap 文件能够获得源文件的具体错误信息,结合 sourcesContent 上源文件的内容进行可视化展现,让报错信息一目了然!
sentry 是一个实时的错误日志追踪和聚合平台,包含了上面 sourcemap 方案,并支持更多功能,如:错误调用栈,log 信息,issue管理,多项目,多用户,提供多种语言客户端等,具体介绍能够查看 getsentry/sentry,sentry.io,这里暂不展开。