Vary与内容协商

Vary 是一个HTTP响应头部信息,它决定了对于未来的一个请求头,应该用一个缓存的回复(response)还是向源服务器请求一个新的回复。它被服务器用来表明在 content negotiationalgorithm(内容协商算法)中选择一个资源代表的时候应该使用哪些头部信息(headers).

在响应状态码为 304 Not Modified 的响应中,也要设置 Vary 首部,而且要与相应的 200OK 响应设置得一模一样。

语法

1
2
Vary: *
Vary: <header-name>, <header-name>, ...
  • *

    所有的请求都被视为唯一并且非缓存的,使用Cache-Control: private,来实现则更适用,这样用于说明不存储该对象更加清晰。

  • 逗号分隔的一系列http头部名称,用于确定缓存是否可用。

##内容协商

HTTP 协议中,内容协商是这样一种机制,通过为同一 URI 指向的资源提供不同的展现形式,可以使用户代理选择与用户需求相适应的最佳匹配

0014

最佳展现形式的选取可以通过两种机制实现:

  • 客户端设置特定的 HTTP 首部 (又称为服务端驱动型内容协商机制或者主动协商机制);这是进行内容协商的标准方式;
  • 服务器返回 300 (Multiple Choices) 或者 406 (Not Acceptable) HTTP 状态码 (又称为代理驱动型协商机制或者响应式协商机制);这种方式一般用作备选方案。

服务端驱动型内容协商机制

HTTP/1.1 规范指定了一系列的标准消息头用于启动服务端驱动型内容协商 (AcceptAccept-CharsetAccept-EncodingAccept-Language)。尽管严格来说 User-Agent并不在此列,有时候它还是会被用来确定给客户端发送的所请求资源的特定展现形式。服务器会使用 Vary 消息头来说明实际上哪些消息头被用作内容协商的参考依据。

请求头字段 说明 响应头字段
Accept 告知服务器发送何种媒体类型 Content-Type
Accept-Language 告知服务器发送何种语言 Content-Language
Accept-Charset 告知服务器发送何种字符集 Content-Type
Accept-Encoding 告知服务器采用何种压缩方式 Content-Encoding
User-Agent 告知服务器发送请求的浏览器,这是不容易的,请参考使用用户代理字段进行浏览器检测

服务端驱动型内容协商机制由于一些缺点而为人诟病——它在规模化方面存在问题。在协商机制中,每一个特性需要对应一个首部。如果想要使用屏幕大小、分辨率或者其他方面的特性,就需要创建一个新的首部。而且在每一次请求中都必须发送这些首部。在首部很少的时候,这并不是问题,但是随着数量的增多,消息体的体积会导致性能的下降。带有精确信息的首部发送的越多,信息熵就会越大,也就准许了更多 HTTP 指纹识别行为,以及与此相关的隐私问题的发生。

Nginx

对于 Nginx 来说,下面这个配置可以自动给启用了 gzip 的响应加上 Vary: Accept-Encoding:

1
gzip_vary on;

IE

为了确保IE6~8不至于客户端cache完全失效,可用 Vary: User-Agent, Accept-Encoding 并开启压缩。

对于IE6,在解压后整个Vary头被丢弃,就OK。
对于IE7和8,解压后AE被去掉,剩下的UA则会被忽略。

IE下的具体问题可以查看 IE与Vary头Vary with Care

代理驱动型内容协商机制

从 HTTP 协议制定之初,该协议就准许另外一种协商机制:代理驱动型内容协商机制,或称为响应式协商机制。在这种协商机制中,当面临不明确的请求时,服务器会返回一个页面,其中包含了可供选择的资源的链接。资源呈现给用户,由用户做出选择。

0015

这种方法主要是通过脚本完成JavaScript 重定向,在检测了协商的条件之后,脚本会触发重定向动作。

参考

Vary https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Vary
内容协商 https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Content_negotiation
Accept 默认值 https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Content_negotiation/Accept_%E9%BB%98%E8%AE%A4%E5%80%BC
使用用户代理字段进行浏览器检测 https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Browser_detection_using_the_user_agent
HTTP 协议中 Vary 的一些研究 https://www.jianshu.com/p/5c601087c18e
IE与Vary头 https://hax.iteye.com/blog/1629953
Vary with Care https://blogs.msdn.microsoft.com/ieinternals/2009/06/17/vary-with-care/
http请求报文头部vary信息 https://www.cnblogs.com/engeng/articles/5981582.html
HTTP请求的响应头部Vary的理解 https://blog.csdn.net/qq_29405933/article/details/84315254