什么可以解释浏览器间歇性地不加载某些 CORS(跨域)javascript 文件?

Mne*_*quo 7 javascript php nginx http-caching cors

我最近将 crossorigin 属性添加到某些脚本标记中,以使我的脚本能够从不同子域的脚本收集错误信息。我在nginx中添加了标头以允许跨域请求。

从那时起,我偶尔会加载页面,而浏览器不会从服务器请求某些 javascript 文件。重新加载页面可以解决该问题,但这种情况已经发生过好几次了。

我认为这与 CORS 有关,但由于它在大多数情况下都有效,所以我不知道如何重现它。

以下是我的代码的一些摘录:

Nginx 配置包含针对某个位置的 javascript 文件的此规则:

add_header 'Access-Control-Allow-Origin' "$http_origin";
Run Code Online (Sandbox Code Playgroud)

我的 php 页面中的脚本标记:

<script type="text/javascript" src="<?php print "$host/js/$filename?v=$version";?>" crossorigin></script>
Run Code Online (Sandbox Code Playgroud)

当我的页面加载时,我可以在 Firebug 中看到脚本标记是正确的,但在 Firebug Net 选项卡中甚至没有显示请求。通常会显示一个请求,即使它使用文件的缓存版本。

我在这里发现了一个我认为可能相关的问题: 我的所有浏览器都没有发送原始标头 但进一步考虑,我认为应该有一个初始请求会失败并会在 Firebug 中显示。

有人对为什么会发生这种情况有任何理论吗?

编辑:我为我的 CORS 请求添加了单独的访问日志。使 Nginx 添加 CORS 标头的位置中的任何文件也会记录在新的访问日志中。

当页面无法加载 JavaScript 文件时,Nginx 会记录一个带有 304 状态(未修改)的请求。这意味着 Nginx 仅在修改后才收到对资源的​​条件请求,并且 Nginx 只发回 304。如果缓存版本未加载 CORS 标头,则可能无法执行 javascript。

我有一个版本号,我将其附加到脚本标记的 src 中,如上所示。此版本号已更改。那么这是否会导致浏览器重新请求所有这些资源,就好像它们具有不同的文件名一样?我认为浏览器应该将这些视为未缓存的资源。不应该有任何可能导致 304 的请求。可能是什么原因导致的?

Mne*_*quo 3

我弄清楚是什么原因造成的。首先,我们需要有关配置的更多信息。

我有 3 个主机:a.my.com、b.my.com 和 c.my.com。静态文件全部由c.my.com提供,html和php由a.my.com和b.my.com提供。

我将 crossorigin 属性添加到我的脚本标记中,以便我可以从脚本中获取有用的错误信息。请参阅此处描述此问题的 SO 问题:Cryptic“Script Error”。Chrome 和 Firefox 中的 Javascript 报告

我使用请求主机作为允许的来源而不是 *,作为将允许的来源列入白名单的先决条件。有关更多信息,请参阅此问题:如何根据请求中的 Origin 标头将 nginx Access-Control-Allow-Origin 正确设置到响应标头中?

我的 nginx 配置对静态内容有很长的有效期,因此内容会被缓存,并且不会通过重复的请求加载我的服务器。我将版本号附加到静态内容的 url 中,以便在发生更改时可以重新请求。版本号来自我在 svn 中的版本,因此当我将服务器文件更新到最新版本时,浏览器都会开始为每个静态文件加载新的 url。

所以这就是发生的事情:

新用户访问 a.my.com 并加载该页面。Javascript 文件 1 到 5 是从 c.my.com 加载的,以便在 a.my.com 上使用。Nginx 向它们发送带有允许“a.my.com”和遥远的未来到期日期的原始标头。该页面工作正常,并且 JavaScript 加载成功。

然后,用户转到 b.my.com 网站的其他部分并加载该页面。Javascript 文件 1 到 10 是从 c.my.com 请求的。文件 1 到 5 与为 a.my.com 加载的文件相同。浏览器知道它的缓存中有这些文件,因此它会向 nginx 询问它们的状态。Nginx 回复 304(未修改),浏览器继续请求下一个文件。

现在浏览器已从 c.my.com 加载文件 6 到 10,并在缓存中查找文件 1 到 5。缓存的文件附加了允许原始标头,这表示“a.my.com”是允许的原点。请求文件的页面位于 b.my.com 上,因此不匹配并且不允许使用它们。因此它会默默地丢弃它们并向用户显示缺少 javascript 的页面。

解决方案:

一种解决方案是发送值为 * 的 Access-Control-Allow-Origin 以允许任何来源。这意味着即使它们没有启动第一次下载,当前源也允许缓存文件。这会带来安全隐患,正如这个 SO 问题中所讨论的:When is it safe to enable CORS?

第二种解决方案是让每个源对同一静态文件使用不同的 url。这迫使浏览器单独缓存它们。这允许 Access-Control-Allow-Origin 标头特定于单个源。代价是更多的资源请求到达服务器,并且用户的浏览器使用更多的内存和存储来缓存资源。

  • 很好的答案。感谢您花时间写下您的发现。 (2认同)