大多数 HTTP 响应包括一个实体,它包含了供人类用户解释的信息。自然,最好是向用户提供与请求相对应的 “最佳可用” 实体。不幸的是,对于服务器和缓存来说,并不是所有的用户都对什么是 “最好的” 有相同的偏好,也不是所有的用户代理都有能力呈现所有的实体类型。出于这个原因,HTTP 规定了几种 “内容协商” 的机制 — 当有多种表现形式可用时,为一个给定的响应选择最佳表现形式的过程。

注意:这不叫 “格式协商”,因为替代的表述可能是相同的媒体类型,但使用该类型的不同功能,用不同的语言,等等。

任何包含 entity-body 的响应都可以被协商,包括错误响应。

在 HTTP 中有两种可能的内容协商:服务器驱动的和代理驱动的协商。这两种协商是正交的,因此可以单独或结合使用。一种组合方法,被称为透明协商,发生在缓存使用由源服务器提供的代理驱动的协商信息,以便为后续请求提供服务器驱动的协商。

12.1 服务器驱动的协商

如果对响应的最佳表示的选择是由位于服务器上的算法进行的,那么它被称为服务器驱动的协商。选择是基于响应的可用表示(它可以变化的维度;例如语言、内容编码等)和请求消息中特定头字段的内容或与请求有关的其它信息(例如客户端的网络地址)。

当从可用的表示中选择的算法难以向用户代理描述时,或者当服务器希望将它的 “最佳猜测” 与第一个响应一起发送给客户时,服务器驱动的协商是有利的(如果 “最佳猜测” 对用户来说足够好,希望避免后续请求的往返延迟)。为了改进服务器的猜测,用户代理可能包括请求头字段(Accept、Accept-Language、Accept-Encoding 等),描述其对这种响应的偏好。

服务器驱动的协商有如下缺点:

  1. 服务器不可能准确地确定什么对任何给定的用户是 “最好的”,因为这需要完全了解用户代理的能力和响应的预期用途(例如,用户想在屏幕上查看还是在纸上打印?)
  2. 让用户代理在每个请求中描述其能力,既可能是非常低效的(考虑到只有一小部分的响应有多种表现形式),也可能是对用户隐私的侵犯。
  3. 它使源服务器的实现和生成对请求的响应的算法复杂化。
  4. 它可能会限制公共缓存对多个用户的请求使用同一响应的能力。

HTTP/1.1 包括以下请求头字段,用于通过描述用户代理能力和用户偏好实现服务器驱动的协商。Accept(第 14.1 节)、Accept-Charset(第 14.2 节)、Accept-Encoding(第 14.3 节)、Accept-Language(第 14.4 节)和 User-Agent(第 14.43 节)。然而,源服务器并不局限于这些方面,它可以根据请求的任何方面改变响应,包括请求头字段以外的信息或本规范没有定义的扩展头字段。

Vary 头字段可以用来表达服务器用来选择受服务器驱动的协商的代表的参数。关于缓存对 Vary 头字段的使用,见第 13.6 节,关于服务器对 Vary 头字段的使用,见第 14.44 节

12.2 代理驱动的协商

在代理驱动的协商中,用户代理在收到来自源服务器的初始响应后,对响应的最佳表示进行选择。选择是基于包含在初始响应的头字段或实体主体中的响应的可用表示的列表,每个表示由它自己的 URI 识别。从代表中的选择可以自动进行(如果用户代理能够这样做),或者由用户从生成的(可能是超文本)菜单中手动选择。

当响应会在常用的维度(如类型、语言或编码)上有所不同时,当起源服务器无法通过检查请求来确定用户代理的能力时,以及通常在使用公共缓存来分配服务器负载并减少网络使用时,代理驱动的协商是有利的。

代理驱动的协商有一个缺点,那就是需要第二次请求来获得最佳的替代性表述。这种第二次请求只有在使用缓存的情况下才是有效的。此外,本规范没有定义任何支持自动选择的机制,尽管它也没有阻止任何这样的机制被开发为扩展并在 HTTP/1.1 中使用。

HTTP/1.1 定义了 300(Multiple Choices)和 406(Not Acceptable)状态代码,用于在服务器不愿意或无法使用服务器驱动的协商提供不同的响应时启用代理驱动的协商。

12.3 透明协商

透明协商是服务器驱动的协商和代理驱动的协商的结合。当缓存被提供了响应的可用表示列表的形式(如在代理驱动的协商中),并且差异的维度被缓存完全理解,那么缓存就有能力代表源服务器对该资源的后续请求执行服务器驱动的协商。

透明协商的好处是,分配了原本需要由源服务器完成的协商工作,而且当缓存能够正确猜测正确的响应时,还可以消除代理驱动的协商的第二次请求延迟。

本规范没有定义任何透明协商的机制,尽管它也没有阻止任何这样的机制被开发为可在 HTTP/1.1 中使用的扩展。