20

我在为以下情况制定 HTTP 缓存标头时遇到问题。

我们的服务器有大量数据,每周可能会更改几次。我希望浏览器缓存这些数据。此外,由于网络不可靠,我想尽量减少条件获取的延迟。

我追求的最终行为是这样的:

  1. 客户端请求它以前没有见过的资源。
  2. 服务器响应资源以及 ETag 和max-age(24 小时)。
  3. 在 24 小时过去之前,客户端将使用缓存的资源。
  4. 过期日期后,客户端将执行验证请求 ( If-None-Match: [etag])
  5. 如果资源没有改变:
    • 服务器响应304 Not Modified
    • 客户以某种方式被告知现有资源在 24 小时后有一个新的到期日期
    • 返回步骤 3

归结为它的本质...... 304 响应是否可以包含一个新的max-age?或者是原始的max-age尊重后续请求?

4

1 回答 1

29

是的,304 响应可以包含一个新的max-age(或 ETag 或其他响应标头)。

我用Firefox 4做了一个实验,测试是使用原始的max-age还是新的,答案是新max-age的,所以你应该能够实现你想做的事情。

重要的是要记住它max-age是相对于Date响应头的,而不是Last-Modified,所以每当你的服务器设置一个max-age24 小时的指令时,它就是说“从现在起 24 小时”。因此,假设这就是您想要的,您根本不必更改您max-age的,只需始终返回 86400。

无论如何,这是我的实验的概述和转储。基本上,我点击了一个设置 ETag 并设置max-age为 120 秒的测试 URL。因此,服务器返回了带有这些响应头的页面:

HTTP/1.1 200 OK
Date: Tue, 14 Jun 2011 23:48:51 GMT
Cache-Control: max-age=120
Etag: "901ea3d0ac9303ae4855a09676f96701"
Last-Modified: Mon, 13 Jun 2011 22:20:03 GMT

然后我在地址栏中重复点击“输入”以加载页面(但不强制重新加载)。没有网络流量,因为 Firefox 反复从缓存中重新加载页面。然后,在 120 秒结束后,就在我下一次按 Enter 时,Firefox 反而向服务器发送了一个条件 GET,正如您所期望的那样。来自服务器的请求和响应是:

GET /example HTTP/1.1
If-Modified-Since: Mon, 13 Jun 2011 22:20:03 GMT
If-None-Match: "901ea3d0ac9303ae4855a09676f96701"

HTTP/1.1 304 Not Modified
Date: Tue, 14 Jun 2011 23:50:54 GMT
Etag: "901ea3d0ac9303ae4855a09676f96701"
Cache-Control: max-age=240

请注意,在 304 响应中,我已将服务器max-age从 120 秒更改为 240 秒。

所以,最大的问题是,120 秒后会发生什么?Firefox 会尊重新的max-age并继续从缓存中加载页面,还是会访问服务器?答案是它继续从缓存中加载页面,直到 240 秒后才重新请求:

GET /example HTTP/1.1
If-Modified-Since: Mon, 13 Jun 2011 22:20:03 GMT
If-None-Match: "901ea3d0ac9303ae4855a09676f96701"

HTTP/1.1 304 Not Modified
Date: Tue, 14 Jun 2011 23:54:56 GMT
Etag: "901ea3d0ac9303ae4855a09676f96701"
Cache-Control: max-age=240

我重复了另一个 240 秒的循环,一切都如你所料。所以,希望这能回答你的问题。

RFC解释了应该如何实现年龄计算,以及其他 Cache-Control 参数如何工作。不能保证每个浏览器和代理都会遵循这些规则,但此时 HTTP 1.1 已经很老了,你会期望它们中的大多数会像 Firefox 那样做。

注意:为简洁起见,在这些示例转储中,我删除了不相关的标头,例如主机、连接/保持活动、内容编码/长度/类型、用户代理等)

于 2011-06-15T00:31:54.737 回答