为什么在上次修改匹配If-modified-since之后Apache会发送200 OK?


10

我正在尝试有关缓存策略的基本行为:应该缓存文件,并每次都使用服务器对其进行重新验证。因此,我希望Apache将304发送回去。

这是每次浏览器刷新都会发生的对话框:

Status Code:200 OK

Request Headers

Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding:gzip,deflate,sdch
Accept-Language:fr-FR,fr;q=0.8,en-US;q=0.6,en;q=0.4
Cache-Control:max-age=0
Connection:keep-alive
Cookie: ...
Host:...
If-Modified-Since:Tue, 14 Oct 2014 15:10:37 GMT
If-None-Match:"1461-505636af08fcd-gzip"
User-Agent:Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.116 Safari/537.36

Response Headers

Accept-Ranges:bytes
Cache-Control:No-cache
Connection:Keep-Alive
Content-Encoding:gzip
Content-Length:1412
Content-Type:text/html
Date:Tue, 14 Oct 2014 16:58:05 GMT
ETag:"1461-505636af08fcd-gzip"
Keep-Alive:timeout=5, max=99
Last-Modified:Tue, 14 Oct 2014 15:10:37 GMT
Server:Apache/2.4.6 (Ubuntu)
Vary:Accept-Encoding

(来自chrome devtools,未选中“禁用缓存”)

您可以看到响应包含Cache-Control:No-cache标头,并且If-modified-since标头与Last-modified匹配。ETag也匹配。

在这种情况下,Apache不应该发送304吗?

编辑

在apache中禁用ETag

 Header  unset ETag

使缓存行为更可预测...


我认为已Cache-Control:max-age=0禁用缓存,因此您会看到Cache-Control:No-cache响应。
ThoriumBR 2014年

我在我的apache配置中明确设置了Cache-Control:No-cache,因为从w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.1,我知道它会导致每个请求的重新验证。重新验证是否意味着重新发送文件?我想说这应该使用如果-修改-因为,以确定它是否是一个200或304
ZRZ

Answers:


8

这似乎是一个古老的错误,解释了为什么Header unset ETag会有所作为。

Apache 2.4.0+自动将压缩方法名称附加到ETag(如标题中所示),并防止304响应。

最新版本的mod_deflate支持可用于控制此行为的DeflateAlterETag

DeflateAlterETag NoChange

3
这是正确的,但是Apache 2.4不包含该选项,仅包含Apache 2.5。但是我个人认为ETags没什么用,因为Apache的依据是上次修改日期,而不是文件内容。因此,关闭ETag会退回到If-Modified-Since标头,该标头始终基于上次修改日期。您可以更改Apache中的ETag以使其基于大小,最后修改的和/或inode的大小(默认大小和最后修改的大小)进行更改,但是直到他们添加一个选项来基于文件内容的校验和计算ETag之前,其有限使用恕我直言。因此,我将其关闭。
巴里·波拉德

1
@BazzaDP有意义。2.5也可以DeflateAlterETag Remove选择执行此操作
Mathias R. Jessen

0

该请求在请求中显得有些奇怪:

Cache-Control:max-age=0

不过,可能更重要的是,我注意到返回的内容是html。它是动态生成的吗?Apache可以发送304响应,但是除非您要提供静态内容,否则进行该调用不是Apache的工作,这取决于您的应用程序逻辑。例如,大多数php应用程序对此类内容的支持有限。

前端缓存可能会有所帮助,因为缓存应用程序可以检查修改时间,etag等,但前提是应用程序和请求标头都对缓存友好。例如,应用程序必须设置适当的标头以指示内容是可缓存的,并且请求中的诸如Cache-control标头之类的东西将使缓存无效。您的标头看起来不适合缓存。


所请求的文件是一个静态html文件,Apache会获得正确的修改时间。(最后修改时间:星期二,2014年10月14日15:10:37 GMT)。当我输入网址并按Enter键时,chrome发送的请求中存在max-age = 0标头。是否因为先前的回应而存在?
zrz 2014年

我了解到Chrome浏览器会自动向请求添加Cache-Control:max-age = 0(除了您第一次加载Chrome时,键入URL,然后按Enter键)。但这似乎并没有影响其他服务器(即使请求中的max-age = 0,CDN也会发送304)。
zrz 2014年

@zrz:调试时限制中间缓存非常有用,否则会影响性能。检查您在chrome上所读内容的上下文。就apache的功能而言,它是可配置的。缓存控制是针对中间缓存(而非原始服务器)的指令。但是,Apache可以充当中间缓存,并且可以配置为执行各种操作。我认为,如果您删除了反缓存说明,您将获得与原始服务器所期望的行为更相似的行为。
mc0e 2014年

0

如果您为Apache配置了Cache-Control:No-cache,则Apache将永远不会向HTTP 304 Not modified客户端发送。

如果要重新验证某些请求,请Cache-Control:No-cache仅在需要的页面上放置一个。您无需重新验证所有资源,并且这样做是在浪费带宽。


我似乎对“重新验证”一词感到困惑。对我来说,这意味着检查它是否为304。我错了吗?
zrz

你错了。重新验证是将所有数据再次发送给客户端,并迫使他再次读取所有内容,即使它已经具有相同的信息。您基本上是在每个客户端上禁用缓存。
ThoriumBR 2014年

这解释了很多。我需要记住的最后一件事是,Apache为某些资源(例如png)发送了304,而我仍然让Cache-Control在响应中没有设置No-cache并在请求中将max-age = 0设置为零。有什么线索吗?
zrz 2014年

@ThoriumBR如果我对您的解释正确,那么您在这里的答案都是错误的;no-cache(与no-store相对)并不意味着“不缓存”,如果内容未更改,可能会导致304。的确,OP希望达到此目的,但由于etag问题而未能实现。must-revalidate与过时内容的处理方式有关,并不总是发送“所有数据”。
尼克
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.