前端错误监控
捕错方式
try catch
我们平时写业务代码时,一般都会使用 try catch,但是 try catch 有以下局限性
无法处理异步代码的错误,如:
try {
setTimeout(() => {
throw Error();
});
} catch (err) {
// 这时候时无法打印错误的
console.log(err);
}无法处理语法错误,如
try {
const a =\ 2
}catch(err){
// 这时候时无法打印错误的
console.log(err)
}
window.onerror
主要捕获运行时 JavaScript 错误。(同步处理)
不能捕获某些资源加载错误(如图片加载失败)
|
window.addEventListener(‘error’)
脚本加载错误(如
<script>
加载失败)。跨域资源加载错误(如图片、视频)。
通常监听的是
ErrorEvent
对象,具有更多属性(如filename
,lineno
,colno
, 和message
)。运行时错误(异步处理)
注意:默认情况下,跨域加载资源的错误信息会因 CORS 限制而不完整。
当静态资源加载失败时,会触发 error 事件, 此时 window.onerror 不能捕获到。原因是window.onerror,是js早期的错误捕捉方案,主要捕获运行时报错,且为同步调用,不依赖事件机制,而脚本资源加载报错这些需要通过事件驱动异步处理。
一般window.onerror捕捉的错误,window.addEventListener(“error”)也能捕捉,差别是window.onerror的兼容性更好,且为同步处理。
如何区分网络资源报错还是其他一般错误?
|
window.onerror
和window.addEventListener('error', callback)
在处理错误时的顺序是不同的。window.onerror
处理错误的优先级要高于window.addEventListener('error', callback)
。也就是说,如果window.onerror
在处理错误时返回了true
,那么window.addEventListener('error', callback)
就不会再处理这个错误。
所以,如果你想让一个错误同时被这两个错误处理机制捕获,并且都能处理这个错误,你需要确保你的window.onerror
在处理错误时返回false
。
window.addEventListener(‘unhandledrejection’)
捕获Promise中抛出的错误
|
框架报错
如使用 vue,需在 vue.config.errorHandler 捕获,也可以重写 console.error,vue 源码里是通过 console.error 报错的
跨域问题
如果当前页面中,引入了其他域名的 JS 资源,如果资源出现错误,error 事件只会监测到一个 script error
的异常。
只能捕获到 script error
的原因:
是由于浏览器基于安全考虑
,故意隐藏了其它域 JS 文件抛出的具体错误信息,这样可以有效避免敏感信息无意中被第三方(不受控制的)脚本捕获到,因此,浏览器只允许同域下的脚本捕获具体的错误信息。
解决方法:
前端 script 加 crossorigin,后端配置 Access-Control-Allow-Origin
接口报错
例如 axios,可以通过 axios 的相应拦截器
sourcemap 还原
我们拿到错误的信息,如果像定位到源码,需要借助 source map,我们打包项目的时候会通过对代码进行压缩、丑化、简化等等,借助 .map 文件可以重新定位源码。
我们打包的时候,需先把 map 文件上传到错误收集数据中心的服务器,当报错上线后可以通过 source map,重新定位。
错误录屏
如果你想进一步发现用户出发错误的行为,需借助前端录屏。行业解决方案:rrweb +webworker+indexDB。核心就是记录 dom。webworker 开线程处理数据,压缩等。indexDB 存储这些大数据,等报错就拿出来上报。
相比于WebRTC,rrweb 这种体积更小,清晰度更高!
rrweb 录制的不是真正的视频流,而是一个记录页面 DOM 变化的 JSON 数组,因此不能录制整个显示器的屏幕,只能录制浏览器的一个页签
rrweb 主要由 rrweb
、 rrweb-player
和 rrweb-snapshot
三个库组成:
1)rrweb:提供了 record 和 replay 两个方法;record 方法用来记录页面上 DOM 的变化,replay 方法支持根据时间戳去还原 DOM 的变化
2)rrweb-player:基于 svelte 模板实现,为 rrweb 提供了回放的 GUI 工具,支持暂停、倍速播放、拖拽时间轴等功能。内部调用了 rrweb 的提供的 replay 等方法
3)rrweb-snapshot:包括 snapshot 和 rebuilding 两大特性,snapshot 用来序列化 DOM 为增量快照,rebuilding 负责将增量快照还原为 DOM
rrweb 整体流程:
1)rrweb 在录制时会首先进行首屏 DOM 快照,遍历整个页面的 DOM 树,转换为 JSON
结构数据,使用增量快照的处理方式,通过 mutationObserver
获取 DOM 增量变化,同步转换为 JSON 数据进行存储
2)整个录制的过程会生成 unique id,来确定增量数据所对应的 DOM 节点,通过 timestamp 保证回放顺序。
3) 回放时,会创建一个 iframe 作为承载事件回放的容器,针对首屏 DOM 快照进行重建,在遍历 JSON 的同时,根据序列化后的节点数据构建出实际的 DOM 节点
4)rrweb 可以监听的用户行为包括:鼠标移动,鼠标交互,页面滚动,视窗变化、用户输入等,通过添加相应的监听事件来实现
参考
- 侯策–《前端开发核心知识进阶》
- 如何从 0 到 1 搭建前端监控平台 - 掘金 (juejin.cn)