12

在服务器被推送到代码库的更新后,有没有办法强制网页的客户端重新加载缓存(即图像、javascript 等)?我们接到很多帮助台电话,询问为什么某些功能不再起作用。一个简单的硬刷新解决了下载新更新的 javascript 文件时的问题。

具体来说,我们使用的是 Glassfish 3.x。和 JSF 2.1.x。当然,这不仅仅适用于 JSF。

描述我希望可能的行为:

网站 A 有两个图像和两个 javascript 文件。用户访问该站点,这 4 个文件被缓存。就我而言,除非用户明确强制“硬”刷新或清除缓存,否则无需“重新下载”所述文件。一旦站点被推送到其中一个文件的更新,服务器可能会在标头中包含某种元数据,通知客户端所述更新。如果客户端选择,将下载新文件。

我不想做的是将元标记放在页面的标题中以强制缓存任何内容......我只想要告诉客户端发生更新的东西,一旦有东西它应该得到最新的已更新。我想这只是客户端的某种版本控制。

谢谢你的时间!

4

2 回答 2

15

处理此问题的正确方法是更改​​资源的 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_______/部分。重写后,它看起来像一个正常的请求,服务器会以正确的文件响应,没有任何其他特定的映射/逻辑......关键是浏览器认为它是一个新文件(即使它真的不是t),所以它请求了它,服务器计算出来并提供正确的文件(即使它是一个“奇怪的”URL)。

当然,另一种选择是将这个动态字符串添加到文件名本身,然后使用重写工具将其删除。无论哪种方式,都做了同样的事情——在重写期间定位一串文本,然后将其删除。这使您可以欺骗浏览器,但不能欺骗服务器:)


更新:

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

  • 检查每个资源
  • 创建一个新文件(或到该文件的映射),其名称是其内容的哈希值
  • <script>/<link>标签添加到您的页面时,将使用散列名称
  • 当请求哈希命名的文件时,它服务于原始资源
  • 以哈希命名的文件被“永远”缓存

这种设置的好处在于您不必担心是否正确缓存 - 只需将文件设置为永久缓存,并且散列应该根据内容处理可用的文件/映射。它还提供了回滚/撤消已经被缓存和快速加载的能力。

于 2013-04-10T21:09:05.500 回答
1

我在这种情况下使用 no-cache 参数...有一个字符串常量值,例如(来自配置文件)

$no_cache = "v11";

在页面中,我使用资产,例如

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

当我更新我的代码时,只需更改 $no_cache 值,它就像一个魅力。

于 2013-04-10T20:51:28.410 回答