我注意到一些浏览器(特别是Firefox和Opera)非常热衷于使用.css和.js文件的缓存副本,甚至在浏览器会话之间。当您更新其中一个文件时,这会导致一个问题,但用户的浏览器会继续使用缓存的副本。

当文件发生更改时,强迫用户浏览器重新加载文件的最优雅的方法是什么?

理想情况下,该解决方案不会强制浏览器在每次访问页面时重新加载文件。


我发现John Millikin和da5id的建议很有用。这有一个专门的术语:自动版本控制。

我在下面发布了一个新的答案,这是我最初的解决方案和约翰的建议的结合。

SCdF建议的另一个想法是将伪查询字符串附加到文件中。(一些自动使用时间戳作为伪查询字符串的Python代码是由pi..提交的)

然而,关于浏览器是否缓存带有查询字符串的文件还存在一些讨论。(请记住,我们希望浏览器缓存该文件并在以后的访问中使用它。我们只希望它在文件更改时再次获取该文件。)


当前回答

我已经通过使用解决了这个问题 ETag:

ETag或实体标签是HTTP的一部分,HTTP是万维网协议。它是HTTP为Web缓存验证提供的几种机制之一,这种机制允许客户机发出有条件的请求。这使得缓存更加高效并节省带宽,因为如果内容没有更改,Web服务器不需要发送完整的响应。ETags还可以用于乐观并发控制,1作为一种帮助防止资源的同步更新相互覆盖的方法。

I am running a Single-Page Application (written in Vue.JS). The output of the application is built by npm, and is stored as dist folder (the important file is: dist/static/js/app.my_rand.js) Nginx is responsible of serving the content in this dist folder, and it generates a new Etag value, which is some kind of a fingerprint, based on the modification time and the content of the dist folder. Thus when the resource changes, a new Etag value is generated. When the browser requests the resource, a comparison between the request headers and the stored Etag, can determine if the two representations of the resource are the same, and could be served from cache or a new response with a new Etag needs to be served.

其他回答

有趣的文章。阅读了这里所有的答案,并结合我从未遇到过任何“伪”查询字符串问题的事实(我不确定为什么每个人都不愿意使用这个),我猜解决方案(它消除了Apache重写规则的需要,因为在接受的答案)是计算CSS文件内容的短哈希(而不是文件日期时间)作为伪查询字符串。

这将导致以下结果:

<link rel="stylesheet" href="/css/base.css?[hash-here]" type="text/css" />

当然,datetime解决方案也可以在编辑CSS文件的情况下完成工作,但我认为这是关于CSS文件的内容,而不是关于文件datetime,所以为什么要把这些混为一谈呢?

你可以把?foo=1234放在CSS / JavaScript导入的末尾,把1234改成你喜欢的任何值。看一下Stack Overflow HTML源代码的例子。

这里的意思是?无论如何,参数都会在请求中被丢弃/忽略,您可以在推出新版本时更改这个数字。


注意:关于这究竟如何影响缓存存在一些争论。我认为它的一般要点是GET请求,无论是否带参数都应该是可缓存的,因此上面的解决方案应该是有效的。

然而,这取决于web服务器和用户使用的浏览器,因为它可以直接要求一个新的版本。

如果你正在使用Git和PHP,你可以在每次Git存储库中有变化时从缓存中重新加载脚本,使用以下代码:

exec('git rev-parse --verify HEAD 2> /dev/null', $gitLog);
echo '  <script src="/path/to/script.js"?v='.$gitLog[0].'></script>'.PHP_EOL;

我不知道为什么你们要花这么大的力气来实现这个解决方案。

您所需要做的就是获取文件修改后的时间戳,并将其作为查询字符串附加到文件中。

在PHP中,我会这样做:

<link href="mycss.css?v=<?= filemtime('mycss.css') ?>" rel="stylesheet">

filemtime()是一个PHP函数,返回修改后的文件时间戳。

谷歌的mod_pagespeed插件将为你自动版本控制。它真的很光滑。

它解析HTML在它的方式从web服务器(与PHP, Ruby on Rails, Python,静态HTML -任何)和重写链接到CSS, JavaScript,图像文件,使他们包括一个id代码。它在修改后的url上提供文件,并对它们进行非常长的缓存控制。当文件更改时,它会自动更改url,因此浏览器必须重新获取它们。它基本上可以正常工作,无需对代码进行任何更改。它甚至还会缩小你的代码。