前端监控是个很庞大丰富的内容,其包含页面UI监控,网络监控,性能监控,错误监控等内容,今天来简单谈谈前端错误监控。
错误种类
这里的前端错误指的是会在控制台抛出的异常,不包括业务逻辑及UI错误。
-
JS语法错误
-
JS运行错误(分为同步错误,异步错误)
-
网络请求错误(分为静态资源加载,异步请求)
-
promise未处理异常
-
跨域脚本异常(script error)
错误收集方法
前端错误的种类不多,但是不同的错误往往需要不同的收集方法,所以完整的错误日志需要不同的收集方法的结合才能全部收集。
try-catch
try-catch 能捕获代码块中的JS运行错误
try {
a
} catch (err) {
// ReferenceError: a is not defined
// at err.html:12
}
try-catch 无法捕获异步错误
try {
setTimeout(() => {
a
})
} catch (err) {
// 无法捕获错误
}
try-catch 无法捕获语法错误
try {
,
} catch (err) {
// 无法捕获错误
}
window.onerror
onerror 可以捕获语法错误和运行时错误
语法错误
/**
* @param {String} msg 错误信息
* @param {String} url 出错文件
* @param {Number} row 行号
* @param {Number} col 列号
* @param {Object} error 错误详细信息
*/
window.onerror = (msg, url, row, column, error) => {
// Uncaught SyntaxError: Invalid or unexpected token
return true; // 控制台不再输出错误
}
,
运行错误
window.onerror = (msg, url, row, column, error) => {
// Uncaught ReferenceError: a is not defined
}
a
异步错误
window.onerror = (msg, url, row, column, error) => {
// Uncaught ReferenceError: a is not defined
}
setTimeout(() => {
a
})
errorEvent
对于静态资源的加载错误我们可以用 window.addEventListener('error') 来捕获
<img src="./404.png" alt="">
能得到的错误信息较少,类型为 error 的事件对象
window.addEventListener('error', (e) => {
// type 为 error
// 可以通过 e.target 来判断是否为静态资源请求错误,避免和 window.onerror 重复收集
}, true);
对于接口的异步请求则需要监听 xhr 实例的方法,例如 load
const xhr = new XMLHttpRequest();
xhr.addEventListener('load', (e) => {
const { responseURL, status, statusText } = e.target;
// example.png 404 Not found
})
xhr.open('GET', 'example.png');
xhr.send();
一般通过 xhr 的实例方法改写来实现错误收集,网上的资料很多,大家可以自行搜索。
unhandledrejectionEvent
现在我们常用 Promise 来解决回调地狱的问题,如果 Promise 的 rejection 状态没被处理会怎么样呢?
Promise.reject(2) // Uncaught (in promise) 2
对于未处理的 rejection 会控制台输出,我们可以使用 unhandledrejection 来捕获
window.addEventListener('unhandledrejection', (e) => {
const { type, reason } = e;
// unhandledrejection 2
e.preventDefault(); // 控制台不再输出reject
})
错误收集方法小结
前面我们介绍了不同的错误收集方法
| JS语法错误 | JS运行错误 | JS异步错误 | 静态资源加载 | 请求异常 | Promise未处理异常 | |
|---|---|---|---|---|---|---|
| try-catch | x | √ | x | x | x | x |
| onerror | √ | √ | √ | x | x | x |
| errorEvent | x | √ | √ | √ | x | x |
| unhandledrejection | x | x | x | x | x | √ |
| 请求事件监听/重写 | x | x | x | x | √ | x |
可以看出,onerror 的功能最强大,可以收集最多错误类型,而且错误内容比较齐全,包含错误位置及错误信息。所以我们可以使用 onerror 作为统一的错误收集方法,同时对 静态资源加载 请求异常 Promise未处理异常 单独进行处理收集。在复杂的业务流程中则使用 try-catch 来做收集,容错处理。
注意防止重复收集。
跨域脚本异常(Script error)
Script error 是浏览器在同源策略限制下产生的,浏览器处于对安全性上的考虑,当页面引用非同域名外部脚本文件时中抛出异常的话,此时本页面是没有权利知道这个报错信息(包括语法错误,运行错误,promise未处理异常)的,取而代之的是输出 Script error 这样的信息。
所以跨域JS脚本的错误详情无法在主页面脚本捕获,只能得到 Script error,而未处理的promise异常也无法在 unhandledrejection 中捕获。
如何解决呢?在脚本标签中加上 crossorigin 属性
<script src="http://localhost:8081/test.js" crossorigin></script>
同时后端服务器按照 CORS 配置可访问域名就行,具体配置参考 CORS(跨源资源共享)
上报
上报方式和正常的请求一样,可以使用
-
img 上报
-
ajax 上报
function report(errInfo) {
new Image().src = 'http://your-api-website?data=' + errInfo;
}
注意:img 请求有长度限制,数据太大最好还是用 ajax.post。
如果遇到错误信息太多的话,可以做了随机过滤
function report(errInfo) {
if (Math.random() > 0.3) {
new Image().src = 'http://your-api-website?data=' + errInfo;
}
}
待完善
由于自己对 sourceMap 的原理及使用方面的知识不足,所以没有研究如何通过 sourceMap 使压缩后的行列和源码位置相对应,后期有研究再补充上。
总结
本文主要是向大家介绍了不同的错误类型及其对应的错误收集方法,如果在业务中有错误监控平台需求的话,还需了解更多的相关知识和业务经验才行。
参考
欢迎来前端菜鸟群一起摸鱼划水~516913974