Script error 产生原因以及解决方法【译】

3,248 阅读3分钟

在使用CDN的时候会出现【Script error】错误,但由于该错误不提供完整的报错信息(错误堆栈),问题无从下手,出于好奇去了解了一下其原理。由于原文档是英文的,故此翻译成中文,分享给大家。 原文地址: 传送门

问题之所在

Script error.

“Script error”是当浏览器跨域请求一个脚本执行出错时,会发起一个onerror错误回调。这就存在问题,因为即使发生了错误,你也不知道是什么错误,同时也不知道是那段代码引起的错误。这就是window.onerror的全部目的——深入的了解应用程序中未发现的错误。 为了更好的去了解发生了什么,假设下面的HTML页面运行在 example.com/test:

<!doctype html>
<html>
    <head>
      <title>example.com/test</title>
    </head>
    <body>
      <script src="http://another-domain.com/app.js"></script>
      <script>
          window.onerror = function (message, url, line, column, error) {
            console.log(message, url, line, column, error);
          }
          foo(); // call function declared in app.js
      </script>
    </body>
</html>

下面是的http://another-domain.com/app.js内容,里边只定义了一个名为name的函数,它总会抛出一个 ReferenceError错误。

// another-domain.com/app.js
function foo() {
  bar(); // ReferenceError: bar is not a function
}

当浏览器加载了这个脚本并开始执行,接下来在控制台会看到以下错误(通过window.onerror的回调打印):

"Script error.", "", 0, 0, undefined

这不是一个bug,是因为出于安全原因,浏览器有意隐藏了来自不同来源的脚本文件的错误。这是为了避免脚本无意中将潜在的敏感信息泄漏给它无法控制的onerror回调。出于这个原因,浏览器只允许window.onerror洞察来之同一域的错误。所以我们只能知道发生了错误,不能知道别的。

解决之方法

为了查看来自不同来源的脚本抛出的错误,必须要执行以下两个操作: 第一,为脚本添加crossorigin="anonymous"

<script src="http://another-domain.com/app.js" crossorigin="anonymous"></script>

这会告诉浏览器这个请求的目标是 anonymously的(即:匿名的),这意味着在请求此文件时,浏览器不会将一些用户标识的信息例如cookies或者HTTP证书等传送给服务器。

第二,设置 Cross Origin HTTP header

Access-Control-Allow-Origin: *

CORS是 Cross Origin Resource Sharing 的缩写,它是一组API(主要是HTTP头),规定了文件应该如何跨源下载和服务。通过设置 Access-Control-Allow-Origin: * ,服务器会向浏览器指示任何源都可以获取此文件。 通过设置全局通配符,你可以指定任何来源都可以使用此服务器。当然如果你想,你可以限制为一个可控的域,例如:

Access-Control-Allow-Origin: http://www.example.com, http://www.another-domain.com

大多数的CND都设置了一个 Access-Control-Allow-Origin 头

当这两个操作都弄好了,这个脚本出现了任何问题都会被window.onerror监听到,就像正常的同一域下的脚本一样。至此,Script error将不再展示,取而代之的是一下错误提示:

ReferenceError: bar is not defined", "http://another-domain.com/app.js", 2, 1, [Object Error]