强制浏览器在更新时重新加载 css


Forcing the browser to reload css when it has been updated

当我在服务器上更新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. 有没有更好的解决方案?

我认为你的方法没有任何问题。更常见的是,这称为缓存无效化或缓存失效。

但是,由于您使用的是 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请求。

  • 设置过期标头:服务器将告诉浏览器文件将在某个日期过期,如果尚未到期,浏览器将不会从服务器请求副本并使用其本地缓存副本。 缺点:如果服务器上的文件在该日期之前更改,浏览器的用户将需要手动执行硬刷新。

这就是为什么我更喜欢只使用缓存破坏参数:我可以将文件的 expires 标头设置为在 5 年后过期。并且浏览器永远不应该对该文件发出 http 请求,除非我更新文件并更改缓存无效化参数。

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

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

core.php相比

根据该文件,这将

将上次修改时间的时间戳应用于静态资产(js, CSS,图像)。将附加一个包含时间的查询字符串参数 文件已修改。这对于使浏览器缓存失效很有用。

这操作起来非常简单,并且在大多数情况下都有效,但是它并非万无一失。大多数代理不会在 URL 中使用"?"缓存资源,因此如果您想修复这些情况,您应该实现更复杂的解决方案,例如 phpdev 建议的解决方案。