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. 有更好的解决方案吗?
4

2 回答 2

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 的请求(可以认为是文件的哈希),如果文件没有改变,服务器会以未修改的 header 响应进行响应。缺点:仍然需要发出 HTTP 请求。

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

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

于 2012-04-16T01:16:17.620 回答
4

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

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

core.php

根据该文件,这将

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

这非常简单,并且在大多数情况下都可以使用,但它并非万无一失。大多数代理不使用“?”缓存资源。在 URL 中,所以如果你想解决这些情况,你应该实现一个更复杂的解决方案,就像 phpdev 建议的那样。

于 2012-05-15T22:10:06.517 回答