不自重者,取辱。不自长者,取祸。不自满者,受益。不自足者,博闻。
用window.onerror捕获并上报Js错误 进入全屏
line

前两天有个2048游戏的用户反馈说,打开游戏后不能玩儿,只有一个游戏面板,数字无法初始化,更无法移动,设备为iPhone 4S、iOS 5.1。尝试从微信调起Safari打开,依然不好使。由于游戏中运用了比较多的HTML5特性,所以粗略估计是有JS报错导致。不过这样的信息该如何捕获到呢?当然是传说中的window.onerror。


W3C找到关于window.onerror的方法体介绍:

这个意思,基本可以就是说,window.onerror方法,我们可以写成:

/**
 * @param {String} 	errorMessage 	错误信息
 * @param {String} 	scriptURI 	    出错的文件
 * @param {Long} 	lineNumber 	出错代码的行号
 * @param {Long} 	columnNumber 	出错代码的列号
 * @param {Object} 	errorObj 	    错误的详细信息,Anything
 */
window.onerror = function(errorMessage, scriptURI, lineNumber,columnNumber,errorObj) { 
    // TODO
}

不过使用过程中还得注意兼容性问题,不是所有浏览器都有参数列表中的所有参数,chrome之类的,都是浏览器标准草案的领跑者,这些个参数用就是了!


于是,可以写一个小Demo来尝试一下:

<!DOCTYPE html>
<html>
<head>
	<title>Js错误捕获</title>
	<script type="text/javascript">
	/**
	 * @param {String} 	errorMessage 	错误信息
	 * @param {String} 	scriptURI 		出错的文件
	 * @param {Long} 	lineNumber 	出错代码的行号
	 * @param {Long} 	columnNumber 	出错代码的列号
	 * @param {Object} 	errorObj 		错误的详细信息,Anything
	 */
	window.onerror = function(errorMessage, scriptURI, lineNumber,columnNumber,errorObj) {
	   console.log("错误信息:" , errorMessage);
	   console.log("出错文件:" , scriptURI);
	   console.log("出错行号:" , lineNumber);
	   console.log("出错列号:" , columnNumber);
	   console.log("错误详情:" , errorObj);
	}
	</script>
</head>
<body>
	<script type="text/javascript" src="error.js"></script>
</body>
</html>

其中error.js文件中的内容,简单的这样写一句:

throw new Error("出错了!");

用浏览器跑起来以后,打开console,基本就是这样的了:

所以,这些数据都是可以做上报的了。


当然了,上面的error.js是和html页面同域名下,如果error.js不在同域下,会是怎样的?我们把error.js的引用改一下:

<script type="text/javascript" src="//doitbegin.duapp.com/error.js"></script>

再来打开console,我们看到的是这样的:

相当于window.onerror方法只捕获到了一个errorMessage,而且是固定字符串,毫无参考价值。查了点资料(Webkit源码),发现在浏览器实现script资源加载的地方,是进行了同源策略判断的,如果是非同源资源,errorMessage就被写死为“Script error”了:

好在script标签有一个crossorigin属性,设置它可以显示比较详细的错误信息,我们试着将script标签改一下:

<script type="text/javascript" src="//doitbegin.duapp.com/error.js" crossorigin></script>

刷新页面,这个时候看到console中的输出是这样的:

出现这个error也不意外,既然设置了error.js为crossorigin,那error.js的HTTP Response Header也必须设置非同源可访问。为了方便设置Header,把error.js做一个小改动,更名为:error-js.php。

<?php
    header('Access-Control-Allow-Origin:*');
    header('Content-type:text/javascript');
?>
throw new Error('出错了');

此时刷新页面,看到console中的输出就已经正常了,所有信息都能正常捕获:


OK,技术细节分析结束!我2048游戏静态资源是放到静态域(非同源)下的,所以要想通过window.onerror捕获错误信息,就得按照上面的最后一种情况来操作了:

1、添加script的crossorigin属性

2、配置一下服务器,设置静态资源Javascript的Response为Access-Control-Allow-Origin


All Done!

趣店(原趣分期)技术学院
重点关注技术架构、服务化、优秀工具、自动化平台、开发全流程一体化解决方案、新人培养、工程师进阶之道等方面
这里环境优雅、氛围年轻、主要是福利还多,还等什么?我们敞开技术的大门,欢迎各种工程师加入!

评论区域

line
  • Alien 2015-01-09 11:05:34 回复
    回复 Kail : 凯子在阿里玩儿得挺爽吧?
    Kail said:
    回复 wilee : 高级浏览器override 掉 HTMLScriptElement.prototype.addEventListener吧
  • Kail 2015-01-09 11:03:47 回复
    回复 wilee : 高级浏览器override 掉 HTMLScriptElement.prototype.addEventListener吧
    wilee said:
    回复 Alien : 那是在同源的JS里写的window.onerror监控非同源的JS嘛,有问题的是在非同源的JS里写的window.onerror监控非同源的JS报错;内网 http://xiongweilie.fe.baidu....
  • Kail 2015-01-09 10:52:09 回复
    回复 Alien : 在head复写掉默认的window.onerror,自己维护一个onerror 的 callback array,这样就行了。这文章还是很有用的,赞,最近也在关注这些内容,还是小晨子转给我看的
    Alien said:
    回复 wilee : 对的,因为各个浏览器对onerror的实现不一样,我们不能通过addEventListener的方式去绑定多个监听。而且在项目中,try-catch也是必须的,只是catch的内容我们...
  • hsl 2014-08-13 10:08:18 回复
    不明白,a按照你这杨获取到的错误信息,貌似没什么用,这里显示的这个get stack: function () { [native code] }东西能看出哪里出错了吗!
  • wilee 2014-04-05 00:34:25 回复
    回复 Alien : 那是在同源的JS里写的window.onerror监控非同源的JS嘛,有问题的是在非同源的JS里写的window.onerror监控非同源的JS报错;内网 http://xiongweilie.fe.baidu.com/v3/test_error.html
    Alien said:
    回复 wilee : 仔细看文章,还得设置httpheader的
  • Alien 2014-04-04 20:01:26 回复
    回复 wilee : 仔细看文章,还得设置httpheader的
    wilee said:
    回复 Alien : 试了下, 发现在非同源引用的JS里写window.onerror也获取不到url参数,同样家了crossorigin属性了的
  • wilee 2014-04-04 19:56:16 回复
    回复 Alien :  试了下, 发现在非同源引用的JS里写window.onerror也获取不到url参数,同样家了crossorigin属性了的
    Alien said:
    回复 wilee : 对的,因为各个浏览器对onerror的实现不一样,我们不能通过addEventListener的方式去绑定多个监听。而且在项目中,try-catch也是必须的,只是catch的内容我们...
  • Alien 2014-04-04 18:49:17 回复
    回复 george wang : 有用就好,多交流。
    george wang said:
    谢谢博主,您的文章解决了我们线上搜集js错误只能拿到"script error"的问题。
  • george wang 2014-04-04 16:44:54 回复
    谢谢博主,您的文章解决了我们线上搜集js错误只能拿到"script error"的问题。
  • Alien 2014-04-04 06:54:10 回复
    回复 wilee : 对的,因为各个浏览器对onerror的实现不一样,我们不能通过addEventListener的方式去绑定多个监听。而且在项目中,try-catch也是必须的,只是catch的内容我们需要视情况而定,进行错误信息上报,且这种情况下,上报的信息更具有分析价值。onerror捕获到的,仅仅是超出我们预知的错误。
    wilee said:
    如果产品线已经使用onerror了,怎么在API里进行错误监控,只有try catch了吗
  • wilee 2014-04-04 00:38:53 回复
    如果产品线已经使用onerror了,怎么在API里进行错误监控,只有try catch了吗
  • Alien 2014-04-01 14:07:38 回复
    回复 heiban : 哈哈,做的还不够,太忙了,我也只能尽量。
    heiban said:
    博主很给力的说,大家反馈的问题跟的都这么及时呢
  • heiban 2014-04-01 14:06:17 回复
    博主很给力的说,大家反馈的问题跟的都这么及时呢
  • Alien 2014-04-01 07:30:26 回复
    回复 你克我服 : 亲,你太给力了!昨天完完整整的忙了一天,没及时回复你,实在抱歉。确实,我这边没有iPhone4的手机,等我去了公司再看看,需要你帮助的话,我就联系你。Thanks
    你克我服 said:
    回复 Alien : 你那里没有iphone4 + ios 5.11的环境?发几个测试用的链接吧,帮你测试一下。好比把这个应用阉割至不同程度,俺测测阉割到哪个程度的版本能正常打开,自然就知...
  • 你克我服 2014-04-01 07:26:17 回复
    回复 Alien : 你那里没有iphone4 + ios 5.11的环境?发几个测试用的链接吧,帮你测试一下。好比把这个应用阉割至不同程度,俺测测阉割到哪个程度的版本能正常打开,自然就知道追加什么的时候出的问题了......
    Alien said:
    回复 你克我服 : 你可以添加公众号“Baidufe”,或者直接添加号码“www_baidufe_com”,回复“game2048”即可。或者你直接到本站首页右下方,扫描二维码添加。
  • 你克我服 2014-03-31 09:36:39 回复
    回复 Alien : 现象依旧,iphone4、打开后没法玩
    Alien said:
    回复 你克我服 : 你可以添加公众号“Baidufe”,或者直接添加号码“www_baidufe_com”,回复“game2048”即可。或者你直接到本站首页右下方,扫描二维码添加。
  • Alien 2014-03-31 09:33:11 回复
    回复 你克我服 : 你可以添加公众号“Baidufe”,或者直接添加号码“www_baidufe_com”,回复“game2048”即可。或者你直接到本站首页右下方,扫描二维码添加。
    你克我服 said:
    现在iphone4要玩2048,链接给一个吧
  • 你克我服 2014-03-31 09:29:30 回复
    现在iphone4要玩2048,链接给一个吧
  • Alien 2014-03-30 22:20:27 回复
    回复 傅小黑 : 哦?应该是有的,我是遇到问题,解决问题,顺便总结一下,哈哈
    傅小黑 said:
    我记得在github看到一个js的tracekit库,可以捕获并打印跟踪
  • 傅小黑 2014-03-30 22:18:34 回复
    我记得在github看到一个js的tracekit库,可以捕获并打印跟踪