Script Error产生的原因及解法

本文来自 阿里云ARMS前端监控团队
“Script error.” 可能是你遇到的最神秘的错误之一, 最让人抓狂的是这种错误没有提供完整的报错信息(错误堆栈), 让排查无从下手.

产生Script Error的原因

“Script error.” 有时也被称为跨域错误. 当网站请求并执行一个托管在第三方域名下的脚本,就可能抛出 "Script error." 最常见的情况是采用CDN托管JS资源.
为了更好地理解“Script error.”, 假设有如下HTML页面,部署在 test.com 域名下



  Test page <span class="hljs-keyword">in</span> http://test.com


  
  


复制代码
假定foo方法中的内容如下, 调用了一个未被定义的bar方法
// another-domain.com/app.js
function foo() {
  bar(); // ReferenceError: bar is not a function
}
复制代码
页面运行之后,捕获到的异常信息如下:
"Script error.", "", 0, 0, undefined
复制代码
其实这并不是一个JavaScript bug, 基于安全考虑浏览器有意隐藏其它域JS文件抛出的具体错误信息。这样可以有效避免敏感信息无意中被第三方(不受控制的)脚本捕获到,因此,浏览器只允许同域下的脚本捕获具体的错误信息。其它脚本只知道发生了一个错误,而不知具体发生了什么错误。
且看 Webkit源码:
bool ScriptExecutionContext::sanitizeScriptError(String& errorMessage, int& lineNumber, String& sourceURL)
	{
	    KURL targetURL = completeURL(sourceURL);
	    if (securityOrigin()->canRequest(targetURL))
	        return false;
	    errorMessage = "Script error.";
	    sourceURL = String();
	    lineNumber = 0;
	    return true;
	}

复制代码
了解了“Script error.”产生的原因, 接下来看看如何解决这类问题。

解法1: 开启CORS跨域资源共享

为了跨域捕获javaScript异常,分两步走

第一步: 添加 crossorigin=”anonymous”属性


复制代码
这一步告诉浏览器,目标脚本通过匿名方式获取。这意味着请求脚本时没有潜在的用户身份信息(如cookies、HTTP 证书等)发送到服务端

第二步: 添加跨域HTTP响应头

Access-Control-Allow-Origin: *
复制代码
或者
Access-Control-Allow-Origin: http://test.com
复制代码
注:大部分主流CDN默认添加了Access-Control-Allow-Origin属性, 如下是阿里CDN的一个示例
$ curl --head https://retcode.alicdn.com/retcode/bl.js | grep -i "access-control-allow-origin"

=> access-control-allow-origin: *
复制代码
完成上述两步之后,跨域脚本的报错就可以通过window.onerror捕获到,回到之前的案例,重新运行之后,捕获到的结果是
=> "ReferenceError: bar is not defined", "http://another-domain.com/app.js", 2, 1, [Object Error]
复制代码

可选解法2: try catch

有时候,不容易往HTTP请求响应头里面添加跨域属性,这时还可以考虑try catch这个候选方案
回到之前的案例



  Test page <span class="hljs-keyword">in</span> http://test.com


  
  


复制代码
再次运行,输出结果如下
=> ReferenceError: bar is not defined
     at foo (http://another-domain.com/app.js:2:3)
     at http://test.com/:15:3

=> "Script error.", "", 0, 0, undefined
复制代码
可以看出来, try catch中的console语句输出了完整的信息, 但window.onerror中只能捕获“Script error.” 基于这个特点,可以在catch语句中,将捕获的异常手动上报。
// 参考阿里云ARMS前端监控API指南 https://help.aliyun.com/document_detail/58657.html
__bl.error(error, pos);   
复制代码
尽管可以通过try catch能够捕获部分异常,但还是推荐尽量采用方式。


你可能感兴趣的:(Script Error产生的原因及解法)