前端异常捕获与上报
能捕获的错误类型
- 语法错误
- 运行时异常
- 资源加载异常
- img
- script
- link
- audio
- video
- iframe
- ...外链资源的DOM元素
- 异步请求异常
- Promise异常
- CSS中资源异常
- font-face
- background-image
- 其他的暂时无法捕获
@font-face
background-image
...暂时无法捕获
捕获方式
- try-catch
- window.addEventListener('error', cb, true)
- window.addEventListener("unhandledrejection", cb)
- Promise.then().catch(cb)
- 定制异步请求代码
代码
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="http://baidu.com/test.js"></script>
</head>
<body>
<img src="sss" onerror="javascript:console.log(this)">
<div>hello world</div>
<script type="text/javascript">
function report() {
(new Image()).src="http://post.error.com?data=xxx"
}
// DOM2
// 全局捕获及时代码运行错误,比如语法错误、逻辑错误
// 还有资源加载错误,通常是404或加载超时
// 第三个参数一定true,为true表示在捕获阶段触发,为false就是冒泡阶段,那获取不到错误事件。
window.addEventListener("error", function(ev) {
console.log('捕获',ev)
}, true);
// DOM4
// 捕获 Promise 未处理的异常
window.addEventListener('unhandledrejection', function(e) {
e.preventDefault();
console.log('捕获到未处理的promise: ', e);
}, false);
new Promise((resolve, reject) => {
reject('jiadsf');
});
fetch('http://example.com/movies.json')
try {
JSON.parse('{123123')
} catch (e) {
// 捕获到JSON.parse的异常,虽然能全局捕获,但找不到错误对象ev.error
}
</script>
</body>
</html>
日志上报
简单版,使用图片。优点实现简单可跨域。
function report() {
(new Image()).src="http://post.error.com?data=xxx"
}
进阶版,使用 Navigator.sendBeacon(),兼容性 Chrome 39+,IE 不兼容。
// navigator.sendBeacon(url, data);
navigator.sendBeacon('http://post.error.com', 'data=xxxxx');
// data 可以传递 string 类型,那么后端接口里接到的请求,Content-Type 为 text/plain,就当字符串处理data
此方法可用于满足统计和诊断代码的需要,可以批量发送数据,并且浏览器保证它不卡渲染线程,在页面 load/unload 事件里处理异步动作而不影响渲染,并且天然跨域。缺点只是兼容性了。
综上上报时优先使用 sendBeancon,监测到不兼容则用 img。
function reportData(url, data) {
if (navigator.sendBeacon) {
navigator.sendBeacon(url, data);
} else {
(new Image()).src = `${url}?data=${data}`
}
}
export default reportData;