"Vary: Accept" HTTP头的作用是什么?

95
我使用PHP生成动态Web页面。如下面的教程所述(请参见下面的链接),当$_SERVER['HTTP_ACCEPT']允许时,XHTML文档的MIME类型应为"application/xhtml+xml"。由于您可以使用2种不同的MIME("application/xhtml+xml"和"text/html")提供相同的页面,因此应将"Vary" HTTP头设置为"Accept"。这将有助于代理服务器上的缓存。

Link: http://keystonewebsites.com/articles/mime_type.php

现在我不确定以下代码的含义: header('Vary: Accept'); 我真的不确定'Vary: Accept'会做什么...

我找到的唯一解释是:

在Content-Type头之后,发送一个Vary 头告诉中间缓存(例如代理服务器), 文档的内容类型根据请求文档的客户端的能力而异, 如果我理解正确的话。 http://www.456bereastreet.com/archive/200408/content_negotiation/

有人可以给我一个关于这个头信息(使用这个值)的“真正”的解释吗? 我想我理解像下面的东西: Vary:Accept-Encoding 代理服务器上的缓存可能基于提供的页面编码,但我不理解: Vary:Accept


1
坦白地说,不要费心了。撇开该网站实现中的缺陷不谈,只有在进行一些无法在text/html中完成的操作时,您才会从使用XML content-type提供服务中获得好处 - 如果您所做的只是切换Doctype和xmlns,那么您将无法完成这些操作。坚持使用text/html。就此而言,您可能也应该坚持使用HTML 4.01。 - Quentin
是的,我理解这一点,我认为像这样的“问题”在Web开发中经常出现。感谢规范/RFC中的“应该”! - AlexV
2
在考虑使用VARY之前,您应该先阅读这篇文章:http://blogs.msdn.com/ieinternals/archive/2009/06/17/Vary-Header-Prevents-Caching-in-IE.aspx。 - EricLaw
2
这个视频很好地解释了Vary:头部信息。 - Kannan Mohan
4个回答

94
  • cache-control头是HTTP服务器告诉缓存代理响应的“新鲜度”(即在缓存中存储响应的时间)的主要机制。

  • 在某些情况下,cache-control指令是不够的。HTTP工作组的一次讨论被存档这里,描述了一个只因语言而改变的页面。这不是vary头的正确用例,但上下文对我们的讨论很有价值。(虽然我认为vary头可以解决那种情况下的问题,但有更好的方法。)从那个页面上:

Vary严格适用于那些代理无法或过于复杂以复制服务器行为的情况。

一个人为的例子:

您的HTTP服务器有一个大型的着陆页面。您有两个略微不同的页面,具有相同的URL,取决于用户之前是否访问过。您基于Cookies区分请求和用户的“访问计数”。但是--由于您的服务器着陆页太大,您希望中介代理尽可能地缓存响应。

URL,Last-Modified和Cache-Control标头不足以向缓存代理提供这种洞察力,但如果您添加Vary:Cookie,则缓存引擎将在其缓存决策中添加Cookie标头。

最后,对于小流量、动态网站--我总是发现简单的Cache-Control: no-cache, no-storePragma: no-cache足够了。

编辑--为了更精确地回答您的问题:HTTP请求头“Accept”定义了客户端可以处理的内容类型。如果您在相同的URL上拥有两个仅在Content-Type方面不同的相同内容副本,则使用Vary:Accept可能是适当的。

更新11 Sep 12:

我在这里附上一些评论中提到的链接,它们都是关于 Vary: Accept 处理实际问题的优秀资源。如果您正在阅读本答案,那么您也需要阅读这些链接。
第一个链接来自杰出的 EricLaw,讨论了 Internet Explorer 使用 Vary 标头时的行为以及开发人员面临的一些挑战:Vary Header Prevents Caching in IE。简而言之,IE(IE9 之前的版本)不会缓存使用 Vary 标头的任何内容,因为请求缓存不包括 HTTP 请求标头。EricLaw(现实世界中的 Eric Lawrence)是 IE 团队的程序经理。
第二个链接来自 Eran Medan,是有关 Chrome 中与 Vary 相关的意外行为的持续讨论:Backing doesn't handle Vary header correctly。它与 IE 的行为有关,但 Chrome 开发人员采取了不同的方法,尽管这似乎不是一个故意的选择。

3
在使用Chrome浏览器的返回按钮时要小心,这个bug引起了一场争论(现在由于某些原因已经被视为无需修复)。http://code.google.com/p/chromium/issues/detail?id=94369 - Eran Medan
6
Chrome 的漏洞已经修复。 - user879121

66

Vary: Accept 的意思是响应是基于请求中的 Accept 头生成的。具有不同 Accept 头的请求可能会得到不同的响应。

(您可以看到链接的 PHP 代码查看 $HTTP_ACCEPT 的值。这是 Accept 请求标头的值。)

对于 HTTP 缓存来说,这意味着必须格外小心地缓存响应。它仅适用于后续请求的 完全相同的 Accept

现在,这只有在第一次缓存页面时才会产生影响。默认情况下,PHP 页面不可缓存。PHP 页面可以通过发送某些头信息(例如 Expires)将输出标记为可缓存。但是否以及如何执行这一点是另一个问题。


是“可能会得到”还是“应该得到”? - Pacerier
6
“可能会得到”是正确的翻译。Vary: Accept并不意味着每一个可能不同的Accept头部值都会产生一个独特不同的响应。它只是表示不同的Accept头部 可能 产生不同的响应。 - Jason Orendorff

2

2
很快就会有一些新功能(Chrome已经实现了)使得 Vary 标头变得极其有用。例如,考虑客户端提示。例如,在与图像一起使用时,客户端提示允许服务器根据以下内容对资源进行优化,如:

  • 图像宽度
  • 视口宽度
  • 浏览器支持的编码方式(WebP)
  • 下行速度(基本上是网络速度)

因此,支持这些功能的服务器将设置 Vary 标头以指示。

Chrome通过将“image/webp”设置为每个请求的 Vary 标头来广告WebP支持。因此,如果浏览器支持WebP,则服务器可能将图像重写为WebP,因此代理需要检查标头,以免缓存WebP图像并将其提供给不支持WebP的浏览器。显然,如果您的服务器不这样做,则无论如何都不重要。因此,由于服务器的响应随着 Accept 请求标头而变化,因此响应必须包含该标头,以避免混淆代理:

Vary: Accept

另一个例子可能是图片宽度。在移动浏览器上,响应式图片的Width头可能比在桌面浏览器上查看时要小得多。因此,在这种情况下,将Width添加到Vary头是代理不缓存小型移动版本并将其提供给桌面浏览器或反之亦然的关键。在这种情况下,头部可能包括:
Vary: Accept, Width

如果服务器支持所有客户端提示规范,则头部将如下所示:

或者在服务器支持所有客户端提示规范的情况下,头部将是以下内容:

Vary: Accept, DPR, Width, Save-Data, Downlink

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