当CSS文件被更新时,强制浏览器重新加载CSS。

4
当我在服务器上更新CSS文件时,许多客户端浏览器会继续使用旧的缓存CSS文件加载页面相当长的时间。
在搜索了许多帖子并汇总不同的想法后,我提出了似乎是最简单和最便宜的方法。
在任何链接CSS文件的地方,将href附加上文件最后修改日期的时间戳,就像这样:
<link rel="stylesheet" type="text/css" href="main.css?t=<?=filemtime('main.css')?>" />

我正在使用CakePHP,所以在布局文件中我做的是:

  <? $t = filemtime(CSS . 'main.css'); ?>
  <?=$html->css("schedule.css?t={$t}") ?>

因此,CSS文件的链接末尾有一个额外的标签,但只要文件没有被修改,它就保持不变。这意味着浏览器将像往常一样将其缓存。但是,一旦文件被修改,链接将会改变,而浏览器也不会错过任何内容。
然而,使用这种方法仍然让人感到有点不妥,因为它并非用于其本意。发送的“消息”没有任何用处,除了识别其存在之外,消息的内容并不重要。
以下是我的问题:
1. 是否承认客户端从浏览器缓存中看到已过时的样式表(或JavaScript)的修订HTML存在风险? 2. 这是一种黑客行为还是合法解决方案? 3. 有更好的解决方案吗?

对于第二个问题:不是的。事实上,它更像是成为一种惯例(如果还没有)。 - Tamer Shlash
对于支持的设备,您可以在清单文件上创建和管理时间(请参见教程:http://www.html5rocks.com/en/tutorials/appcache/beginner/)。附加的时间戳被广泛使用,但可能是更好的解决方案。 - rjz
2个回答

4
CakePHP有一个非常简单易用的解决方案。只需要取消注释此行即可:

//Configure::write('Asset.timestamp', true);

来自 core.php

根据该文件,此操作将会:

在静态资源(js、css、图像)上应用最后修改时间戳。会附加一个查询字符串参数,其中包含文件修改的时间。这对于使浏览器缓存失效非常有用。

这种方法非常简单,并且大多数时候都能正常工作,但它并不是万无一失的。大多数代理服务器不会缓存带有“?”的 URL 资源,因此如果您想解决这些情况,您应该实现一个更复杂的解决方案,就像 phpdev 建议的那样。


4
我认为你的方法没有问题。通常情况下,这被称为缓存破坏或缓存失效。
然而,因为您使用的是像这样的URL:http://site.com/assets/mystyle.css?29320202020,所以可能会遇到CDN的问题。CDN将看到GET参数并认为这是动态请求,因此它将向您的服务器请求文件,这就破坏了在CDN中具有缓存副本的目的。
我的做法是将缓存破坏参数包含在文件名中:http://site.com/assets/mystyle.2390202202.css。我使用优秀的Assetic库来完成这个任务,并编写了一些简单的代码,以便我的模板知道它需要mystyle.css,而mystyle.2390202202.css是由Assetic动态生成并插入到模板中的。
这种方法应该可以让您很好地处理CDN,同时获得缓存破坏功能。
其他可能的解决方案:
- ETags:浏览器将使用ETag(可以视为文件的哈希值)向服务器发送请求,如果文件未更改,服务器将响应未修改的头响应。缺点:仍需要进行HTTP请求。 - 设置过期标头:服务器将告诉浏览器文件将在某个日期过期,如果还没有到那个日期,浏览器将不会从服务器请求副本并使用其本地缓存的副本。缺点:如果文件在日期之前在服务器上更改,浏览器的用户将需要手动进行硬刷新。 这就是为什么我更喜欢只使用缓存破坏参数的原因:我可以将文件的过期标头设置为在5年后过期。除非我更新文件并更改缓存破坏参数,否则浏览器不应该为该文件发出HTTP请求。

“Cache busting”这个术语很有用,可以帮助在谷歌搜索时更容易找到。但是,查询字符串会导致浏览器每次都下载文件吗?我会进行一些测试。我还不确定是否应该接受这个答案,因为我仍然相信应该有更好的方法告诉浏览器有一个新版本的文件,而不是使用PHP框架来重命名它。 - Jason Galuten
我更新了我的答案,并提供了其他可能的解决方案,但我认为缓存破坏可能是最好/最有效的。 :) - F21

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接