大多数响应包含一个实体,此实体包含人类用户能理解的信息。通常,希望提供给用户相应于请求最容易得到的实体。对服务器和缓存来说,不幸的是,并不是所有的用户都对这个最容易得到的实体有喜好,并且并不是所有的用户代理(如web浏览器)都能一致的呈现这些实体。所以,HTTP提供了一些“内容协商”机制 — 当有多个可得的表现形式的时候,对特定的响应选择最好的表现形式的处理过程。
注意:没有称做“格式协商”(译注:“格式”指的是“媒体类型”)的,因为可替换的表现形式可能会同原来的有相同的媒体类型,只是利用了此媒体类型不同的性质,例如一种不同的语言。
任何包含一个实体主体的响应包括错误响应都可能会受协商的支配。
有两种类型的内容协商在HTTP中:服务器驱动协商和代理驱动协商。这两种类型的协商具有正交性并且能被单独使用或联合使用。一个联合使用方法的协商会被叫做透明协商,当缓存利用代理驱动协商的信息的时候,此代理驱动协商的信息被为后续请求提供服务器驱动协商的源服务器提供。
一、 服务器驱动协商(Server-driven Negotiation)
如果响应的最好的表现形式的选择是通过服务器上的算法来实现,那么这种方式的协商称做服务器驱动协商。选择是基于响应可得的表现形式(根据不同的维度,响应会不同;例如,语言,内容编码,等等)和请求消息里特定的头域或关于请求的其他信息(如:网络客户端的地址)。
服务器驱动协商是有优点的,当从可行的表现形式里进行选择的算法对用户代理进行描述是比较困难的时候(译注:代理驱动协商),或者当服务器期望发送“最好的猜测”给客户端而只通过一个响应(以避免后续请求的回路(一个请求会返回一个响应)延迟如果此“最好的猜测“对用户适合的时候)的时候。为了改善服务器的猜测,用户代理应该包含请求头域(Accept,Accept-Language,Accept-Encoding,等等),这些头域能描述它对响应的喜好。
服务驱动协商有如下缺点:
- 对服务器不可能确切的决定对用户来说什么是最好的,因为那需要对用户代理和用户对此响应目的的全面理解(如:用户到底想把响应展示到屏幕还是打印到纸上?)。
- 使用户代理描述请求里的能力是非常无效的(假设只有响应的一小部分有多个表现形式)还有会侵犯用户的隐私。
- 使源服务器的实现变得复杂,也对为请求产生响应的算法实现变得复杂。
- 可能会限制公有缓存(public cache)为多个客户请求利用相同响应的能力
HTTP/1.1包含下面的请求头域来使服务器驱动协商启动,这些请求头域描述了用户代理的能力和用户喜好:Accept,Accept-Charset,Accept-Encoding,Accept-Language,和User-Agent。然而,一些源服务器并不只局限于这些维度,这些服务器能基于请求的任何方面来让响应不同,这些方面包括请求头域之外的信息或在此规范里没有定义的扩展头域。
Vary头域能被用来表达服务器选择表现形式(representation)利用的参数,表现形式受服务器驱动协商的支配。
Accept: Which media types are acceptable for the response, such as “application/json,” “application/xml,” or a custom media type such as "application/vnd.example+xml"
Accept-Charset: Which character sets are acceptable, such as UTF-8 or ISO 8859-1.
Accept-Encoding: Which content encodings are acceptable, such as gzip.
Accept-Language: The preferred natural language, such as “en-us”.
二、代理驱动协商 (Agent-driven Negotiation)
对代理驱动协商来说,响应的最好表现形式的选择被用户代理执行,这在接收到源服务器一个初始的响应后。选择是基于响应的一系列可得的表现形式,这些表现形式被包含在初始响应的头域或初始响应的实体主体(entity-body)里,每个表现形式被一个属于自己的URI指定。从这些表现形式中选择可能被自动执行(如果用户代理有能力这样做)或者被用户从超文本连接菜单中手工选择。
代理驱动协商是有优点的,当响应可能会根据一般用途的维度(如:类型,语义,编码)而不同的时候,当源服务器不能通过查看请求而判定用户代理能力的时候,当共有缓存(public cache)被用来分派服务器的承载和减少网络使用的时候。
代理驱动协商也同样存在需要第二次请求而获得最好表现形式的缺点。第二次请求只有当缓存被使用时才是有效率的。另外,此规范没有定义用户代理自动选择表现形式的机制,所以不能防止任何这样的机制被用于HTTP/1.1
HTTP/1.1定义了300(多个选择)和406(不接受的)状态响应,当使用代理驱动协商时服务器不能或不愿意利用服务器驱动协商来提供一个不同的响应的是时候。
三、 透明协商(Transparent Negotiation)
透明协商是服务器驱动协商和代理驱动协商的结合体。当一个缓存被提供了构成响应的一系列可得的表现形式(就像在代理驱动协商里的响应一样)并且维度的差异能完全被缓存理解,那么此缓存变得有能力代表源服务器为那个资源的后续请求去执行服务器驱动协商。
透明协商的优点在于它能分发源服务器的协商工作并且能移去代理驱动协商的第二次请求的延迟,因为缓存能正确的猜测到合适的响应。
此规范没有定义透明协商的机制,所以,它不能防止任何这样的机制被用于HTTP/1.1。
ASP.NET Web API支持内容协商: 客户端和服务器可以一起从API返回的数据,以确定正确的格式. 我们提供了默认的XML支持, JSON的, 和表格的URL编码格式, 你可以扩展这种支持,通过添加自己的格式化, 甚至取代默认内容的谈判策略.
本文来自云栖社区合作伙伴“doNET跨平台”,了解相关信息可以关注“opendotnet”微信公众号