前端异常监控、上报及js压缩代码定位

最近在研究前端异常监控的问题,对查询的资料作了整理汇总,整体以下html

1、前端异常监控方式

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;
};
复制代码

注意:webpack

  • 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。ios

window.addEventListener("unhandledrejection", function(e){
    e.preventDefault()
    console.log('我知道 promise 的错误了');
    console.log(e.reason);
    return true;
});
复制代码

3.iframe 错误

父窗口直接使用 window.onerror 是没法直接捕获,若是你想要捕获 iframe 的异常的话,有分好几种状况。git

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字段跨域等等github

3)若是是非同域且网站不受本身控制的话,除了经过控制台看到详细的错误信息外,没办法捕获

2、监控上报

监控拿到报错信息以后,接下来就须要将捕捉到的错误信息发送到信息收集平台上,经常使用的发送形式主要有两种:web

  • 经过 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);
}
复制代码

3、JS代码压缩后,如何定位

该部分原文出处:https://github.com/joeyguo/blog/issues/14axios

示例:跨域

1.源代码(存在错误)

function test() {
    noerror // <- 报错
}

test();
复制代码

2.经 webpack 打包压缩后产生以下代码

!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()}]);
复制代码

3.代码如期报错,并上报相关信息

{ 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,查找起来比普通压缩方便很多。但仍会出现一行中有不少代码,不容易定位的问题。

方案二:js 代码半压缩 · 保留空格和换行

uglifyjs 的另外一配置参数 beautify 设置为 true 时,最终代码将呈现压缩后进行格式化的效果(保留空格和换行),如

!function(n) {
    // ...
    // ...
}([ function(n, r) {
    function t() {
        noerror;
    }
    t();
} ]);
复制代码

此时,错误信息中行列数为 32 和 9,可以快速定位到具体位置,进而对应到源代码。但因为增长了换行和空格,因此文件大小有所增长。

方案三:SourceMap 快速定位

SourceMap 是一个信息文件,存储着源文件的信息及源文件与处理后文件的映射关系。 在定位压缩代码的报错时,能够经过错误信息的行列数与对应的 SourceMap 文件,处理后获得源文件的具体错误信息。

SourceMap 文件中的 sourcesContent 字段对应源代码内容,不但愿将 SourceMap 文件发布到外网上,而是将其存储到脚本错误处理平台上,只用在处理脚本错误中。 经过 SourceMap 文件能够获得源文件的具体错误信息,结合 sourcesContent 上源文件的内容进行可视化展现,让报错信息一目了然!

sourceMap

方案四:开源方案 sentry

sentry 是一个实时的错误日志追踪和聚合平台,包含了上面 sourcemap 方案,并支持更多功能,如:错误调用栈,log 信息,issue管理,多项目,多用户,提供多种语言客户端等,具体介绍能够查看 getsentry/sentry,sentry.io,这里暂不展开。

sentry

参考文章:

  1. 跨域,你须要知道的全在这里
  2. 脚本错误量极致优化-让脚本错误一目了然
  3. 前端代码异常监控实战
相关文章
相关标签/搜索