window.onerror的总结

作者: 牧羊童鞋 | 来源:发表于2017-10-08 21:05 被阅读6430次

最近一直在做前端js错误监控的工作,在不断的打磨和完善中,发现里面还是知识点不少,现在就前端js错误监控做一些笔记和总结

我们知道前端js错误监控主要是利用了window.onerror函数来实现,onerror函数会在页面发生js错误时被调用。

window.onerror = function(message, source, lineno, colno, error) { ... }

我们可以看到函数正常是可以收集到错误字符串信息、发生错误的js文件,错误所在的行数、列数、和Error对象(里面会有调用堆栈信息等)。

我们只需要把这些信息回传到server端即可,再配合sourcemap的话我们就可以知道是源码中的哪一行出错了,从而实现完美的错误实时监控系统了。然而要完美还是需要做很多工作的。

首先,我们的js文件一般都是和网站不同域的,这是为了提高页面的渲染速度以及架构的可维护性(单独CDN域名,充分利用浏览器http并发数)。这样的js文件中发生错误我们直接监控你会发现你啥信息都收集不到。

实验一:我们的站点是a.com,页面中引用了两个js文件,一个是a.com域名下的a.js,一个是b.com域名下的b.js,我们在a.js文件中添加window.onerror监控,在b.js文件中主动抛出错误

<!-- index.html  -->
<script type="text/javascript" src="http://a.com/a.js" ></script>
<script type="text/javascript" src="http://b.com/b.js" ></script>
// a.js
window.onerror = function (message, url, line, column, error) {
  console.log('log---onerror::::',message, url, line, column, error);
}
// b.js
throw new Error('this is the error happened in b.js');

我们可以看到下图的结果,onerror函数拿到的信息是Script error, a 0 null,啥卵用都没有,你完全不知道发生了什么错误,哪个文件发生的错误。

这是浏览器所做的安全限制措施,当加载自不同域(协议、域名、端口三者任一不同)的脚本中发生语法(?)错误时,为避免信息泄露,语法错误的细节将不会报告,而代之简单的"Script error."

实验一的结果

但是我们确实是需要知道发生错误的具体信息啊,不然监控就没有意义了。既然又是类同源限制的问题,那肯定是可以通过CORS来解决了。

实验二:我们给b.js加上Access-Control-Allow-Origin:*的response header,后面我们会发现还是没啥变化。

实验二的结果

实验三:我们继续给b.js加上crossorigin属性,发现可以了,想要的信息都收集到了,nice

<!-- index.html  -->
<script type="text/javascript" src="http://a.com/a.js" ></script>
<script type="text/javascript" src="http://b.com/b.js"  crossorigin></script>
实验三的结果

结论:如果想通过onerror函数收集不同域的js错误,我们需要做两件事:

  1. 相关的js文件上加上Access-Control-Allow-Origin:*的response header
  2. 引用相关的js文件时加上crossorigin属性

注意: 以上两步缺一不可。实验二告诉我们,如果只是加上Access-Control-Allow-Origin:*的话,错误还是无法捕获。如果只加上crossorigin属性,浏览器会报无法加载的错误,如下图

仅仅加上crossorigin属性的script加载结果

可是。。。
如果你使用sentry的raven.js的话,你会发现你什么都不用做,他依然可以帮你捕获到一些错误的非常具体信息,确实是有点神奇啊,具体怎么做的?关键就是raven源码中的install方法中调用的_instrumentTryCatch函数起了作用,他通过tryCatch的方式wrap了一些关键函数,使得这些函数里的报错能够捕获,_instrumentTryCatch的具体实现原理我们后面再说

    install: function() {
        var self = this;

        if (self.isSetup() && !self._isRavenInstalled) {
            TraceKit.report.subscribe(function () {
                self._handleOnErrorStackInfo.apply(self, arguments);
            });
            if (self._globalOptions.instrument && self._globalOptions.instrument.tryCatch) {
              self._instrumentTryCatch();// 通过tryCatch来wrap关键函数,从而获得error的具体信息
            }

            if (self._globalOptions.autoBreadcrumbs)
                self._instrumentBreadcrumbs();

            // Install all of the plugins
            self._drainPlugins();

            self._isRavenInstalled = true;
        }

        Error.stackTraceLimit = self._globalOptions.stackTraceLimit;
        return this;
    },

其实如果你真的什么都不做,raven也只是能捕获一些异步错误,同步错误还是无法捕获,所以你即使使用了sentry等第三方的错误收集库,你还是需要加上Access-Control-Allow-Origin:*和crossorigin属性

image.png

参考文献:
GlobalEventHandlers.onerror
What the heck is "Script error"?

相关文章

  • window.onerror的总结

    最近一直在做前端js错误监控的工作,在不断的打磨和完善中,发现里面还是知识点不少,现在就前端js错误监控做一些笔记...

  • window.onerror

    在打点系统中会监控页面的运行时报错,在上报错误时会使用window.onerror来进行全局监控 但是由于浏览器安...

  • js错误收集

    window.onerror = function(msg, url, line, col, error, err...

  • ie6怪癖--随时更新

    1、不认识:position:relative; 2、 window.onerror=function(){re...

  • 【衣柜减法】远没有那么难

    window.onerror = function() { return true; }女生都喜欢买买买,然后一股...

  • 错误监控

    监听事件 类型同步异步页面资源(img)Promisetry/catch✔️window.onerror✔️✔️w...

  • js异常捕获

    一、js异常捕获的两种方式: 1、try...catch2、window.onerror try...catch ...

  • 如何优雅的处理异常

    可疑区域增加 Try-Catch 全局监控 JS 异常 window.onerror 全局监控静态资源异常 win...

  • 前端容错

    一、两个脚本独立执行,彼此是不影响的 二、try,catch 三、window.onerror 四、 error监...

  • Web前端错误监控

    脚本运行时错误捕获 window.onerror 监听全局错误发生,发生错误会阻止后续的脚本运行 try - ca...

网友评论

  • 0bfce20a708e:我们给b.js加上Access-Control-Allow-Origin:*的response header 你是怎么给js加的呢,可以给个截图么
    0bfce20a708e:@牧羊童鞋 好的 谢谢
    牧羊童鞋:ngin配置下就好了, https://segmentfault.com/a/1190000012550346
  • 0bfce20a708e:学习了

本文标题:window.onerror的总结

本文链接:https://www.haomeiwen.com/subject/nejyyxtx.html