为什么客户端不会在 public 文件夹中收到此脚本的新版本?

Why won't the client receive new versions of this script in the public folder?

在我的项目中有一个public文件夹,里面有一个脚本:public/worker.js,里面有一段代码:

alert('foo');

我使用 Worker 调用此脚本:

new Worker('worker.js');

我启动 Meteor 并连接到我的应用程序。 foo 收到警报。
如果我将 public/worker.js 代码更改为其他代码:

alert('bar');

服务器刷新客户端,客户端刷新页面但不会获取新代码,而是使用旧代码(提醒 foo 而不是新的闪亮 bar)。清除缓存然后刷新可以解决此问题。 CTRL+F5 没有解决这个缓存问题,它似乎不适用于这种脚本调用(至少在我测试过的 Firefox 版本上不行)。

为什么会这样?
我该如何预防?

您应该更改文件的响应 header。也许这会让你前进:Explicit HTTP Response Headers for files in Meteor's public directory

脚本已缓存,浏览器不会从服务器拉取新版本。

我们需要编辑 header 对 /workers 文件夹中文件的请求,使用以下代码 server-side(我将其包装在一个包中 api.use('webapp')):

WebApp.rawConnectHandlers.use('/workers', function(req, res, next) {
  res.setHeader('cache-control', 'must-revalidate');
  next();
});

使用WebApp.connectHandlers没有用,回调从未被调用,所以我改用rawConnectHandlers

我不是 100% 确定这是最好的方法,但它确实有效。

我还没有找到确切的原因,但浏览器(至少 Chrome)似乎在页面刷新缓存方面以不同于其他 Javascript 文件的方式对待工作脚本,即使从服务器发送的 headers 是相同的。刷新页面会使浏览器检查脚本标记中引用的新脚本,但不会检查用作工作程序的脚本。

我解决这个问题的方法是,在构建时,我在文件名中包含文件内容的 number/build time/md5 版本,所以它最终会像 worker.12333.js。这样做的好处是,如果每个文件名引用一个本质上不可变的文件,你可以设置 far-future expires headers... 所以不是告诉浏览器永远不要缓存工作脚本,它可以缓存它永远。 https://github.com/felthy/grunt-cachebuster 就是这样一种工具,可以通过脚本标签为 Javascript 执行此操作,但可能还有其他工具。

这个问题是必须有某种机制告诉 Javascript 更新的文件名,所以它知道调用 new Worker('worker.12333.js');。我不确定现有的可用工具是否可以处理这个问题,但我这样做的方法是只使用以秒为单位的项目构建时间作为所有文件的唯一键

<html build-time="12333">
  ...

然后通过 Javascript 访问它,这样它就可以计算出最新的工作脚本文件名。它并不完美,但相当简单。您可能会根据您的要求提出其他机制。