强制浏览器在网站更新后重新加载所有缓存

13
有没有一种方法可以强制网页客户端重新加载缓存(例如图片、JavaScript等),在服务器推送代码更新后?我们接到很多帮助台电话,询问为什么某些功能不再起作用。简单的硬刷新可以解决问题,因为它会下载新更新的 JavaScript 文件。
具体而言,我们使用 Glassfish 3.x 和 JSF 2.1.x。这当然适用于不止 JSF。
我希望实现的行为是这样的:网站 A 有两个图像和两个 JavaScript 文件。用户访问该站点,并缓存这 4 个文件。只要用户不强制进行“硬”刷新或清除缓存,就没有必要“重新下载”这些文件。一旦网站中的一个文件被更新,服务器将在标头中包含某些元数据,通知客户端已经更新了该文件。如果客户端选择,新文件将被下载。
我不想在页面头部放置元标签来防止任何内容被缓存......我只想要一些东西告诉客户端发生了更新,一旦更新了某些内容,它应该获取最新版本。我想这只是一种客户端版本控制的方式。
谢谢您的时间!
2个回答

16

正确的处理方法是更改资源的URL约定。例如,我们有以下形式:

/resources/js/fileName.js
为了让浏览器仍然缓存文件,但以正确的方式使用版本控制,需要在URL中添加一些内容。将值添加到查询字符串中不允许缓存,因此将其放置的位置是在/resources/之后。
关于查询字符串缓存的参考:http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.9 例如,您的URL将如下所示:
/resources/1234/js/fileName.js

那么你可以使用项目的版本号(或者在属性/配置文件中的某个值),当你想要重新加载缓存文件时手动更改该值,因为这个数字只应该在项目被修改时才会改变。因此,你的URL可能如下所示:

/resources/cacheholder${project.version}/js/fileName.js

这应该很容易。

现在的问题在于映射URL,因为中间的那个值是动态的。我们克服这个问题的方法是使用URL重写模块,在请求到达我们的应用程序之前过滤URL。重写会检查看起来像下面这样的URL:

/resources/cacheholder______/whatever
并且移除了cacheholder_______/这部分。重写后,它看起来像一个正常的请求,服务器会响应正确的文件,无需任何其他特定的映射/逻辑...关键是浏览器认为它是一个新文件(即使实际上并不是),所以它请求了它,服务器找到了正确的文件并提供服务(即使它是一个“奇怪”的URL)。
当然,另一种选择是将这个动态字符串添加到文件名本身中,然后使用重写工具将其删除。无论哪种方式,都是做同样的事情-针对重写期间的文本字符串,并将其删除。这允许您欺骗浏览器,但不能欺骗服务器 :)

更新:

我非常喜欢的另一种选择是根据内容设置文件名,并缓存。例如,可以使用哈希来完成。当然,这种类型的事情不是你手动完成并保存到你的项目中的(希望如此);这是你的应用程序/框架应该处理的事情。例如,在Grails中,有一个插件可以“散列和缓存”资源,因此会发生以下情况:

  • 检查每个资源
  • 创建一个新文件(或映射到此文件),名称为其内容的哈希
  • 在页面中添加<script>/<link>标记时,使用散列名称
  • 请求哈希命名的文件时,它会提供原始资源
  • 哈希命名的文件被永久缓存

这种设置的有趣之处在于,您不必担心正确缓存-只需将文件设置为永久缓存,哈希应该处理基于内容的文件/映射可用性。它还提供了回滚/撤消已经被快速缓存和加载的能力。


根据我阅读的文档,“向查询字符串添加值不允许缓存”这个说法是不准确的。浏览器无论是否有查询字符串,都会缓存HTTP GET请求。参见http://www.w3schools.com/tags/ref_httpmethods.asp。 - pmont
@pmont请不要引用W3Schools而非实际的W3文档。您的观点是无效的,请阅读我发布的链接或提供更合法的内容。 - Ian
1
不要对我发脾气。我部署的Web服务器都缓存了查询URL。你观察到哪些服务器没有缓存它们?从你提供的链接中可以看到:“这意味着HTTP/1.0服务器对于这样的URI的响应不应该从缓存中获取。”也许HTTP/1.1的变化可以解释不同的行为? - pmont
2
@pmont 这可能解释了为什么使用 http1.0 查询存在问题 https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html - Souhaieb Besbes

1
我会翻译中文,以下是内容翻译:

在这种情况下,我使用了一个不缓存的参数......我有一个字符串常量值(来自配置文件)

$no_cache = "v11";

在网页中,我使用像这样的资源:


<img src="a.jpg?nc=$no_cache">

当我更新我的代码时,只需更改$no_cache的值,它会像魔法一样正常工作。

但正如你所指出的,这样做永远不会允许资源被缓存。为什么你想要这样做呢? - Ian
1
如果您不更改no_cache值,静态文件将被缓存。只有在更改了静态内容时才进行更改。 - tanaydin
不,那不是真的。根据HTTP规范,任何带有查询字符串的内容都不应该被缓存。一些浏览器会遵循这个规范,而一些则不会。因此,由于末尾有查询字符串,浏览器总是会发起请求。服务器可能已经将其缓存,这很好,但在客户端仍然没有被缓存。 - Ian
2
@Ian,您误解了您提供的网址中的陈述,它与HTTP1.0服务器有关,而不是大多数服务器今天使用的HTTP1.1服务器。 - Souhaieb Besbes

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