谷歌浏览器未向服务器发送if-modified-since头信息。

53

我有这些由服务器发送到客户端的头信息:

Cache-Control:private
Connection:keep-alive
Content-Encoding:gzip
Content-Type:text/html
Date:Sun, 27 Nov 2011 11:10:38 GMT
ETag:"12341234"
Set-Cookie:connect.sid=e1u...7o; path=/; expires=Sun, 27 Nov 2011 11:40:38 GMT; httpOnly
Transfer-Encoding:chunked
last-modified:Sat, 26 Nov 2011 21:42:45 GMT

我希望客户端能够验证服务器上的文件是否已更改,如果未更改则发送“200”,否则发送“304”。

Firefox 发送:

if-modified-since: Sat, 26 Nov 2011 21:42:45 GMT
if-none-match: "12341234"

为什么刷新页面时Chrome没有发送相同的内容?我希望的行为是与.Net运行时相同的:

context.Response.Cache.SetCacheability(HttpCacheability.ServerAndPrivate)

我不理解"I'm after the behavior that .Net has running:"。你能编辑一下吗?这个问题对我很重要。 - Anders Lindén
这只是在 .Net 中运行代码后 : 后面的行为。看着标签,我试图在 node.js 中模仿这种行为。 - Asken
对于那些认为这是客户端问题并投票支持这些答案的所有人,请阅读以下内容:由于我使用etag(if-none-match)发出浏览器请求,因此这与服务器有关,而与客户端无关。 Etag是由服务器端创建的,与客户端无关。我需要知道的是从服务器发送到客户端的内容,以使它在Chrome中也发送etag标头。选择的答案是唯一正确的,因为它告诉服务器也发送 if-none-match - Asken
即使看起来不是这样,也请注意,如果您直接从地址栏请求图像,则Chrome不会发送“If-Modified-Since”头。仅当从“img”标签或任何与图像相关的css属性请求时,才从缓存中检索图像。 - Daniels118
6个回答

72
经过昨天半天的努力,我找到了导致我的问题的原因。只要你在Chrome中开启了对象检查器/客户端调试器/网络监视器/按下F12时弹出的东西,Chrome就不会发送缓存请求标头。无论如何。(更新:在较新版本的Chrome中,有一个名为“禁用缓存”的复选框) 即使您没有打开“网络”选项卡(例如,打开了JavaScript控制台),此复选框仍会禁用所有缓存。
这很糟糕,因为从客户端的角度调试这个问题需要您打开网络面板以查看发送和接收的标头以及返回的代码。如果没有打开网络面板,则无法知道您的内容是否从客户端缓存。
如果您深入研究服务器访问日志,您会注意到关闭Chrome客户端上的调试窗口后,服务器立即返回304s(已缓存的内容)。希望这可以帮到你。
Chrome 24.0.1312.57

53
开发工具有一个选项 "在 DevTools 打开时禁用缓存",也许你已经启用了这个选项?点击右下角的 '齿轮' 图标,检查你的设置。 - Neek
1
+1(是的,您需要取消选中“在打开DevTools时禁用缓存”)。 - Kerem
3
这不是答案,而答案与服务器有关。 - Asken
2
这个答案是一个很好的提示(并且它确实导致了解决方案,即在Neek的评论中),但是不幸的是它是错误的。防止标题的不是打开devtools,而是勾选“禁用缓存”。@Neek的评论才是真正的答案,他/她应该考虑将其作为一个答案。 - Bad Request
2
如果我理解正确的话,答案不能与服务器有关,因为If-Modified-Since是一个请求头。因此,它必须由客户端发送。 - Bad Request
这在(几乎)2022年和Chrome v95中仍然是如此。 - oligofren

39
我发现了一个关于使用HTTPS时出现这种行为的答案,想分享一下我所发现的。你没有说明是通过HTTP还是HTTPS请求。
"规则实际上非常简单:证书出现任何错误都意味着页面不会被缓存。"

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

如果您使用的是自签名证书,即使您告诉Chrome添加了一个例外,以便页面可以加载,该页面中没有任何资源会被缓存,而且后续的请求也不会有If-Modified-Since头。

这似乎不再是真的了。我有一个页面,浏览器会为某些资源发送“if-modified-since”头,但对于其他资源则不会发送。 - pbanka
与之前的评论相反,我确实看到了完全相同的行为。在我有一个无效证书的环境中,并没有发送If-Modified-Since,但是当我有一个有效证书时,它就被发送了。 - dmccabe
谢谢,我也遇到了这个问题。 我在开发机上使用自签名证书进行测试。 作为一个测试,我暂时信任了证书,并开始得到预期的304。 - Steviebob
在我们优化一些包含的库时,我们注意到了同样的问题。自签名证书或针对不同域的证书会导致脚本文件完全无法缓存。浏览器在请求时没有发送 if-modified-since 或 if-none-match 标头。切换到 HTTP 或通过证书的 DNS 到相同的服务器将使浏览器包含这些标头。 - Pyro
2
向您竖起大拇指!4年后,这个似乎是正确的答案。当在本地环境中使用自签名/忽略证书时,Chrome永远不会发送If-None-Match头。 - Tony Bogdanov
这就是真正的答案,应该是最佳答案。我已经浪费了半天时间,疯狂地尝试,但一直没有弄清楚。事实证明,在Safari中它可以轻松运行。 - rednoah

16

根据我的经验,你需要除了“私有”Cache-Control头之外,还需使用“Max-Age”或“Expires”来强制Chrome与服务器重新验证内容。

请记住,只有在经过这些时间值后,重新验证才会开始,因此它们可能需要设置为一个较小的值。


1
我尝试了 cache-control: private, max-age=0,但不起作用...还有其他的想法吗?我还添加了 expires 头,但仍然无效。 - Asken
实际上...应该是max-age=100000或者其他的值。差不多快搞定了。有时候需要发送if-none-match,这就是出问题的地方。谢谢! - Asken
我通常将 Max-age 设置为1小时,但它完全取决于您更新静态内容的频率。如果不确定,请保持值较低以确保安全。 - Andy McCluggage
1
你们中有人找到了真正的解决方案吗?我也遇到了同样的问题,它会时不时地发送。我可以重新加载页面5次,但它似乎是随机的,无法确定是否会将其发送回来。 - Tim Lieberman
是的,正如我所说,这一切都与添加Max-Age或Expires标头有关。您需要明确何时内容可能过时,否则浏览器将使用其自己的算法,这可能是不可预测的,就像您所见过的。据我的经验,当您提供这些额外信息时,总是可以获得可预测的行为。 - Andy McCluggage
我只能获取包含Cache-Controlmax-ageLast-ModifiedExpires头的标头。 - Alex S

4

4
未勾选禁用缓存,问题仍然存在。我正在运行版本号为58.0.3029.110(64位)的浏览器。 - Reado
只需打开DevTools即可。这是Chrome中的一种错误。 - oligofren

1
浏览器在缓存方面有很多反直觉的行为。您可能会期望,如果响应包括最后修改日期,浏览器会在重用之前重新验证它。但是,所有主要的浏览器实际上都没有这样做。
对于您的情况,理想的设置取决于您希望浏览器何时重新验证,请参见下面的链接。
不仅浏览器的行为反直觉,而且不同的浏览器在相同的情况下也表现不同。例如,当用户单击刷新按钮时。
您可以阅读不同浏览器(Internet Explorer、Edge、Safari、FireFox、Chrome)如何使用不同的缓存指令(Etag、last-modified、must-revalidate、expires、max-age、no-cache、no-store)在https://gertjans.home.xs4all.nl/javascript/cache-control.html中的行为。

0

我知道这个问题很老了,但是还是要说一下... 我注意到Chrome会记住你最后一次刷新的操作。所以如果你按下ctrl+shift+r(刷新并删除缓存),然后再按下ctrl+r(只是刷新),Chrome会继续删除缓存,并且不会在接收到的响应中显示304。有一个解决方法。按下ctrl+shift+r,然后转到地址栏,将其聚焦,并按下回车键。如果你的ETag设置正确,并且你的服务器准备好提供304,则调试器中会出现一个新的响应代码-304。所以它可以正常工作。


我在多个网站上观察到了这种行为。无论是客户端错误还是其他问题,了解有时候cmd+r可能不足够仍然是很有帮助的。 - M K
1
采纳的答案将帮助那些出现问题的网站,而不会强迫网站用户做他们不应该做的事情。 - Asken
我的回答并不是作为已接受答案的替代品 :) 它只是额外的信息。 - M K
您可以在问题下方使用评论进行讨论。阅读与问题无关的“答案”会令人困惑。 - Asken
  1. 这个注释太长了。
  2. 我曾经遇到同样的问题,在这里找不到解决方案,后来自己找到了一个解决方法,回来分享了我的解决方案。你无法知道它是否正确!它与Qeremy的答案一样,都是关于Chrome缓存的。我只是想为其他遇到同样问题的可怜人节省时间。不过,随意删除它。
- M K
谢谢您提到这一点,我从来没有想到普通刷新和地址栏上的CR之间有区别。即使调试面板打开,这也可以正常工作。 - AgilePro

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