刷新缓存的CSS数据

47

如何强制浏览器刷新缓存的CSS?

这并不像每个请求那样简单。我们的网站已经稳定使用CSS一段时间了。

现在我们需要对CSS进行一些重大更新,但是已经缓存了CSS的浏览器将在几天内无法获取新的CSS,从而导致渲染问题。

是否有一种方法可以强制刷新CSS,还是我们最好选择特定版本的CSS URL?


您可以在以下链接中找到一份热键清单,用于强制浏览器进行“硬重置”,以清除缓存。https://en.wikipedia.org/wiki/Wikipedia:Bypass_your_cache#Bypassing_cache - Gino
4个回答

63

简而言之

  • 更改文件名或查询字符串
  • 使用每个版本中仅发生一次的更改
  • 更改文件名优先于更改查询字符串
  • 始终设置HTTP头以最大化缓存效益

有几个要考虑的问题和各种方法来解决这个问题。首先,规范

我们要达到什么目标?

理想情况下,修改后的资源将在第一次请求时无条件地获取,并在过期之前从本地缓存中检索,而不需要任何后续服务器交互。

观察到的缓存行为

跟踪不同的排列组合可能有点混乱,所以我创建了以下表格。这些观察是通过从Chrome对IIS进行请求并在开发者控制台中观察响应/行为来生成的。

在所有情况下,新URL将导致HTTP 200。重要的是看 后续 请求会发生什么。

+---------------------+--------------------+-------------------------+
|        Type         |   Cache Headers    |     Observed Result     |
+---------------------+--------------------+-------------------------+
| Static filename     | Expiration +1 Year | Taken from cache        |
| Static filename     | Expire immediately | Never caches            |
| Static filename     | None               | HTTP 304 (not modified) |
|                     |                    |                         |
| Static query string | Expiration +1 Year | HTTP 304 (not modified) |
| Static query string | Expire immediately | HTTP 304 (not modified) |
| Static query string | None               | HTTP 304 (not modified) |
|                     |                    |                         |
| Random query string | Expiration +1 Year | Never caches            |
| Random query string | Expire immediately | Never caches            |
| Random query string | None               | Never caches            |
+---------------------+--------------------+-------------------------+

然而,请记住浏览器和Web服务器并不总是按我们的预期行事。一个著名的例子:2012年移动Safari开始缓存POST请求。开发人员并不满意。

查询字符串

以ASP.Net MVC Razor语法为例,但几乎适用于任何服务器处理语言。

由于一些应用程序传统上使用GET和HEAD与查询URL(在rel_path部分中包含“?”)执行具有重大副作用的操作,因此缓存必须除非服务器提供显式的到期时间,否则不能将对这样的URI的响应视为新鲜的。特别是,HTTP / 1.0服务器对于此类URI的响应不应该从缓存中获取。

在HTML中包含的CSS URL的末尾添加一个随机参数将强制发出新请求,服务器应该用HTTP 200进行响应(即使它没有被修改,也不是304)。

<link href="normalfile.css?random=@Environment.TickCount" />

当然,如果我们每次请求都随机生成查询字符串,这将完全破坏缓存。 对于生产环境应用程序来说,这通常是不可取的/从不可取的。

如果您只维护少量的URL,您可以手动修改它们以包含构建号或日期:

@{
    var assembly = Assembly.GetEntryAssembly();
    var name = assembly.GetName();
    var version = name.Version;
}

<link href="normalfile.css?build=@version.MinorRevision" />

第一次用户代理遇到URL时将引发新请求,但后续请求通常会返回304。这仍会引发请求,但至少不会服务整个文件。

路径修改

更好的解决方案是创建一个新路径。通过一些努力,可以自动化此过程,以重新编写带有版本号(或其他一些一致的标识符)的路径。

这个答案展示了一些非Microsoft平台的简单而优雅的选项。

Microsoft开发人员可以使用HTTP模块拦截给定文件类型的所有请求,或可能利用MVC路由/控制器组合来提供正确的文件(我没有看到过这样的做法,但我相信这是可行的)。

当然,最简单的方法(不一定是最快或最佳的方法)就是在每次发布时重命名所涉及的文件,并在link标记中引用更新的路径。


啊,我喜欢这个想法。 - m.edmondson
15
好的,我会遵循您的要求进行翻译。以下是需要翻译的内容:Put the TLDR first ^^ :) - sam

8
我认为重命名CSS文件是一个更好的主意。这可能不适用于所有应用程序,但它将确保用户只需加载一次CSS文件。在末尾添加一个随机字符串,将确保他们每次都需要下载它。 以上所述的JavaScript方法和Apache方法也是类似的情况。 有时候简单的答案可以是最有效的。
另一个解决方案是:
<FilesMatch "\.(js|css)$">
    Header set Cache-Control "max-age=86400, public"
</FilesMatch>

这将限制最大缓存时间为1天或86400秒。


2
请先阅读Tim Medora的答案,因为这是一个非常有知识性和伟大的帖子。
现在我会告诉您如何在PHP中实现它。我不想麻烦于传统版本控制或尝试维护1000多个页面,但我想确保用户始终获得我的CSS的最新版本并将其缓存。
因此,我使用查询字符串技术和PHP filemtime(),它将返回上次修改的时间戳。
该功能返回写入文件的数据块的时间,即更改文件内容的时间。
在我的Web应用程序中,我使用一个config.php文件来存储我的设置,因此在此我将创建一个像这样的变量:
$siteCSS = "/css/standard.css?" .filemtime($_SERVER['DOCUMENT_ROOT']. "/css/standard.css");

然后在我的所有页面中,我将像这样引用我的CSS:
<link rel="stylesheet" type="text/css" media="all" href="<?php echo $siteCSS?>" />

到目前为止,在 PHP/IIS 上这一直很好用。

即使使用版本控制,这仍是确保更改的绝佳方式。我喜欢它,因为它在开发过程中仍然有效。 - Tim Morton

0

你可能可以在Apache中完成它...

<FilesMatch "\.(html|htm|js|css)$">
FileETag None
<IfModule mod_headers.c>
Header unset ETag
Header set Cache-Control "max-age=0, no-cache, no-store, must-revalidate"
Header set Pragma "no-cache"
Header set Expires "Wed, 11 Jan 1984 05:00:00 GMT"
</IfModule>
</FilesMatch>

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