最近在研究前端异常监控的问题, 对查询的资料做了整理汇总, 总体如下
一, 前端异常监控方式
1. window.onerror 异常处理
window.onerror 无论是异步还是非异步错误, onerror 都能捕获到运行时错误.
- window.onerror = function (msg, url, row, col, error) {
- console.log('我知道错误了');
- console.log({
- msg, url, row, col, error
- })
- return true;
- };
复制代码
注意:
1)window.onerror 函数只有在返回 true 的时候, 异常才不会向上抛出, 否则即使是知道异常的发生控制台还是会显示 Uncaught Error: xxxxx.
2)window.onerror 是无法捕获到网络异常的错误. 由于网络请求异常不会事件冒泡, 因此必须在捕获阶段将其捕捉到才行, 但是这种方式虽然可以捕捉到网络请求的异常, 但是无法判断 HTTP 的状态是 404 还是其他比如 500 . 还需要配合服务端日志才进行排查分析才可以.
- window.addEventListener('error', (msg, url, row, col, error) => {
- console.log('我知道错误了');
- console.log(
- msg, url, row, col, error
- );
- return true;
- }, true);
复制代码
2. Promise 错误
Promise 实例抛出异常而你没有用 catch 去捕获的话, onerror 或 try-catch 也无能为力, 无法捕捉到错误. 如果用到很多 Promise 实例的话, 特别是你在一些基于 promise 的异步库比如 axios 等一定要小心, 因为你不知道什么时候这些异步请求会抛出异常而你并没有处理它, 所以你最好添加一个 Promise 全局异常捕获事件 unhandledrejection.
- window.addEventListener("unhandledrejection", function(e){
- e.preventDefault()
- console.log('我知道 promise 的错误了');
- console.log(e.reason);
- return true;
- });
复制代码
3.iframe 错误
父窗口直接使用 window.onerror 是无法直接捕获, 如果你想要捕获 iframe 的异常的话, 有分好几种情况.
1) 如果你的 iframe 页面和你的主站是同域名的话, 直接给 iframe 添加 onerror 事件即可.
- <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>
复制代码
2) 如果你嵌入的 iframe 页面和你的主站不是同个域名的, 但是 iframe 内容不属于第三方
可以通过与 iframe 通信的方式将异常信息抛给主站接收. 与 iframe 通信的方式有很多, 常用的如: postMessage,hash 或者 name 字段跨域等等 https://github.com/happylindz/blog/issues/3
3) 如果是非同域且网站不受自己控制的话, 除了通过控制台看到详细的错误信息外, 没办法捕获
二, 监控上报
监控拿到报错信息之后, 接下来就需要将捕捉到的错误信息发送到信息收集平台上, 常用的发送形式主要有两种:
通过 Ajax 发送数据
动态创建 img 标签的形式
- 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);
- }
复制代码
三, JS 代码压缩后, 如何定位
- function test() {
- noerror // <- 报错
- }
- test();
- { msg: 'Uncaught ReferenceError: noerror is not defined',
- url: 'http://127.0.0.1:8077/main.min.js',
- row: '1',
- col: '515' }
- !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()}])
- !function(n) {
- // ...
- // ...
- }([ function(n, r) {
- function t() {
- noerror;
- }
- t();
- } ]);
来源: https://juejin.im/post/5b55c3495188251acb0cf907