HTTP:结合过期和验证缓存

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仅适用于后续请求?

1个回答

29

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

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

重要的是要记住,max-age是相对于响应头中的Date而不是Last-Modified的时间,因此每当服务器设置24小时的max-age指令时,它表示“从当前时间开始的24小时”。因此,假设这就是你想要的,你不需要改变你的max-age,只需始终返回86400即可。

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

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

然后我重复在地址栏中按“Enter”加载页面(但不强制执行硬刷新)。由于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一样做。

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


1
我随后重复在地址栏中按“回车”以加载页面(但不强制进行硬刷新)。这是我需要自己进行实验的关键信息!感谢您提供了经过深入研究的答案! - roufamatic
3
我用Firefox复现了您所描述的情况。在Chrome中,按下地址栏中的"回车"键仍会导致304。我发现访问另一个页面(例如google.com),然后点击返回按钮,可以显示所需的缓存行为。(有趣的是,如果我通过"前进"按钮进入我的页面,它总是显示缓存文件。) - roufamatic
谢谢,这是关于Chrome的好信息。我想,如果你正在测试,主要的事情就是尝试模拟用户所做的任何操作,无论是点击链接还是点击书签(直接访问),可以从引荐数据中估计出来(我猜这两者都会从有效缓存加载)。并按浏览器进行分解。或者只是相信Firefox/Chrome,并且高兴地实现HTTP正确地实现你所想要的。 - joelhardi
因此,在测试浏览器缓存如何工作时(至少在Chrome中),请在新标签页中打开所需的URL,然后您可以转到一些新的URL,然后点击返回。对我来说,在地址栏中使用ENTER和F5肯定会导致强制重新加载。 - Vitaly Sazanovich
有人得到了这个答案吗?- http://stackoverflow.com/questions/26964948/force-browser-to-send-always-if-none-match-when-max-age-is-expired-but-was-i - Codebeat

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