一,内容协商的基本原则
内容协商是当有资源有多种表示可用时,为给定响应选择最佳表示的过程:
- 一份特定的文件称为一项资源。整个资源,连同它的各种表现形式,共享一个特定的 URL 。
- 当客户端想要获取资源的时候,会使用其对应的 URL 发送请求。
- 服务器通过这个 URL 来选择这个请求指向的资源的某一变体——每一个变体就是资源的一种表现形式——然后将这个选定的表现形式返回给客户端。
二,为什么会有内容协商
同一项资源可以有不同的表现形式,简单来说就是不同的数据格式.
举个比较具体的例子,比如使用这样一个 URL 时:http://127.0.0.1:8000/books/v1,客户端既可以显式地通过指定后缀的方式指定所需要的格式:http://127.0.0.1:8000/books/v1/1.pdf 或者http://127.0.0.1:8000/books/v1/1.html等,也可以通过显式地通过指定关键字的方式指定所需要的格式:http://127.0.0.1:8000/snippets/v1/1?format=xml 或者 http://127.0.0.1:8000/snippets/v1/1?format=json等。
这样显得非常直观,但却并不符合 RESTful URL的定义(RESTful URL的定义本身就是对 HTTP 提供的基础设施的充分利用),也并不一定能让客户端的请求得到真正的满足:万一服务器无法返回该资源的某种特定表示呢?
基于这两点,客户端与服务器在与资源实体的相关的信息交互中,应该做这样几件事:
- 客户端剥离 URL 中除资源本身之外的格式信息,交由 HTTP 中的基础设施进行实现。
- 服务器以默认(或者说最佳)的表现形式在响应中返回资源实体。
总之,有这样一些关键看法:
- 应该充分利用 HTTP 协议提供的特性,减少不必要的自定义行为。
- 请求不是命令,要什么,就双方协商着来,这样能够屏蔽客户端之间的差异,从而实现长期的 URL 功能。
- 之所以叫内容协商而不叫格式协商,是因为内容可被视为格式的超集,而不仅仅是具体的媒体类型
media_type
。
Content Negotiation in RFC 2616
Understanding Content Negotiation in Web API
Why would HTTP content negotiation be preferred to explicit parameters in an API scenario?
Content Negotiation For Web API Longevity
三内容协商机制
客户端和服务器端之间存在多种协商方式,有些已经被逐渐淘汰了。这里只介绍两种最主要的方式:
- 如果响应的最佳表示是由位于服务器的逻辑进行的,则称为服务器驱动的内容协商。
- 如果响应的最佳表示是在代理或客户端进行的,则称为代理驱动的内容协商。
1,服务器驱动的内容协商
1,当客户端发送 HTTP 请求时,它可以通过请求头中的 Accept
指定它可以接受的媒体类型。举个例子🌰:
Accept: text/xml, application/xml, application/json
客户端也能指定特殊供应商的媒体类型。举个例子🌰:
application/vnd.ms-excel
application/vnd.sif.v2.studentpersonal+json
客户端可以通过Accept
、Accept-Charset
、 Accept-Encoding
、Accept-Language
指定详细的响应要求。
2,服务器接收请求后,根据内容协商规则选择最合适的类型,在设置 Content-Type
以包含实际发送的资源类型、使用的字符集、编码方式、内容语言等信息后返回。
如果客户端发发送的请求不包含 Accept
,则服务器可以自由地提供它认为最好的任何表示。
总之,就是服务器根据客户端的请求头的情况,决定:
- 在 HTTP 响应中返回一种表示
- 重定向到包含请求的表示之一的不同 URL
- 发送 415错误(不支持的媒体类型)
3,客户端接收到响应后,就根据 Content-Type
对响应进行解析。
即便服务驱动型内容协商机制相对直观,但它存在如下几个缺点:
- 实际上,服务器可返回它认为合理的一切,而并不完全遵守于客户端的要求。
- 因为给定的资源需要返回不同的展现形式,共享缓存的效率会降低,而服务器端的实现会越来越复杂。
- 面对不同的资源请求,可能会导致客户端需要使用越来越复杂的请求头内容。
2,客户端/代理驱动的内容协商
1,客户端首先通过 URL 发送请求。
2,服务器会在遇到模棱两可的请求时返回一个页面,该页面包含指向该资源所有可用表示的链接。
3,客户端合适的链接,再次发送请求。
4,服务器解析请求,设置 Content-Type
指定请求所需要的表示,并返回。
5,客户端接收到响应后,就根据 Content-Type
对响应进行解析。
在确保内容协商成功率时,这也导致一些问题:
- HTTP 标准没有指定用于在可用资源之间进行选择的页面格式,、除了回退到服务器驱动的协商之外,这种方法几乎总是与额外的脚本一起使用:在检查协商标准后, JavaScript 脚本执行重定向。
- 需要一个额外的请求来获取真正的资源,减慢了资源对用户的可用性。
Content negotiation
Accept 与 Content-Type
Apache HTTP Server Version 2.4 Content Negotiation
Content Negotiation
Content Negotiation in REST
HTTP协议的内容协商