Chrome不会发送“If-Modified-Since”请求头

10

我希望浏览器在除第一次访问外,每次都添加"If-Modified-Since"请求头以避免不必要的流量。

响应头如下:

Accept-Ranges:bytes
Cache-Control:max-age=0, must-revalidate
Connection:Keep-Alive
Content-Length:2683
Content-Type:text/html; charset=UTF-8
Date:Thu, 05 Apr 2012 13:06:19 GMT
Keep-Alive:timeout=15, max=497
Last-Modified:Thu, 05 Apr 2012 13:05:11 GMT
Server:Apache/2.2.21 (Red Hat)

FF 11和IE 9都发送了"If-Modified-Since"头部,并得到了304的响应,但Chrome 18没有发送,却得到了200的响应。

为什么?如何强制Chrome发送"If-Modified-Since"头部? 我不知道这是否重要,但所有请求都通过HTTPS进行。


最终,是否缓存内容取决于浏览器和任何中间缓存(您可以控制它们是否应该缓存)。您无法100%防止用户代理重新请求内容。 - Damien_The_Unbeliever
3
我注意到Chrome只有在响应被gzip压缩时才会发送"If-Modified-Since"请求头。我不确定这是否是一种真正的模式,还是只是我的经验在尝试更新JS文件时的体验。 - Ryan
发送 Keep-Alive 的特定原因是什么? - Julian Reschke
6个回答

29

我花了一些时间追踪这个问题,想分享我找到的东西。

"规则实际上很简单:任何证书错误都意味着页面不会被缓存。"

https://code.google.com/p/chromium/issues/detail?id=110649

如果您正在使用自签名证书,即使告诉Chrome添加一个例外让页面加载,该页面的资源也不会被缓存,并且后续请求将没有If-Modified-Since标头。


7
我刚才发现了这个问题,在研究Chrome的"If_Modified_Since"行为后,我找到了答案。
Chrome缓存文件的决定基于它收到的"Expires"头信息。 "Expires"头信息有两个主要要求:
1. 必须使用格林威治标准时间(GMT); 2. 必须按照RFC 1123(基本上是带有四位数字年份的RFC 822)格式化。
格式如下:
Expires: Sat, 07 Sep 2013 05:21:03 GMT

例如,在 PHP 中,以下代码将输出一个格式正确的标题。
$duration = time() + 3600 // Expires in one hour.
header("Expires: " . gmdate("D, d M Y H:i:s", $duration) . " GMT");

("GMT"被附加到字符串中,而不是使用"e"时区标志,因为当与gmdate()一起使用时,该标志将输出"UTC",而RFC 1123认为这是无效的。还要注意PHP常量DateTime::RFC1123DATE_RFC1123将不会提供正确的格式,因为它们输出的是与GMT的差异(即+02:00),而不是"GMT"。)
有关更多信息,请参见W3C的日期/时间格式规范
简而言之,只有遵循这种确切格式,Chrome才能识别标题。这与Cache-Control标头相结合...
header("Cache-Control: private, must-revalidate, max-age=" . $duration);

我使用适当的缓存控制头使Chrome开始缓存我发送的页面(甚至带有查询字符串!),并开始发送If_Modified_Since头。我将其与存储的“last-modified”日期进行比较,返回HTTP/1.1 304 Not Modified,一切都运行得很完美。

希望这能帮助其他遇到同样问题的人!


2
谢谢,GMT时区是我的问题,我没有注意到 :) - Martin Zvarík

5

我发现几乎相同的行为,我的发现如下:

  • 首先,在Chrome中的200状态指示器并不是全部的真相,你需要查看“大小内容”列。如果这个说“(from cache)”那么资源是直接从缓存中取出而不会询问是否已被修改。

  • 这种缓存行为似乎适用于请求静态文件并带有last-modified头部的资源。我注意到Chrome(ver.22):

    1. 第一次请求文件(显然因为它不在缓存中)。
    2. 第二次询问它是否被修改(因为它在缓存中但没有新鲜度的指示)。
    3. 第三次及以后直接使用它(即使是新的浏览器会话)。
  • 我对这种行为感到有些困惑,但它是相当合理的,如果它是静态的,很久以前被修改过,并且自上次检查以来没有变化,那么你可以假设它将在更长时间内有效(不知道他们是如何计算的)。


嗨@Albert Bertilsson,第一次请求文件** 2. ** 3. **,这是你的结论吗?我认为这不正确,Chrome缓存使用的策略应该是LM-Factor,而不是你说的那个。如果您从Google官方文档中引用了此内容,请粘贴链接,非常感谢。 - materliu
关于你最后提到的点,浏览器如何知道一个文件是静态的? - Michael Scheper

3

我曾经遇到过相同的问题,在Chrome浏览器中,所有请求的状态代码都是200,而在其他浏览器中则是304。

后来发现我在开发者工具-设置-通用页面上勾选了在开发者工具打开时禁用缓存 :)


2
  1. 不要在Chrome Dev Tools(“Network”标签页)中禁用缓存。
  2. Cache-Control应该为Cache-Control: public。使用true作为header PHP函数的第二个参数:header("Cache-Control: public", true);

0
我还发现Chrome(最近的v95+)如果我打开了DevTools,它也会返回一个缓存的200响应。它甚至不会将请求发送到服务器!如果我关闭DevTools,行为就如预期一样,服务器会接收到预期的请求。

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