文章目录
  1. 1. 如何标明客户端偏好
    1. 1.1.
  2. 2. 如何实现媒体类型协商
  3. 3. 如何实现语言协商
  4. 4. 如何实现字符编码协商
  5. 5. 如何支持压缩
  6. 6. 何时及如何发送Vary头
  7. 7. 如何处理协商失败
  8. 8. 如何使用代理驱动的内容协商
  9. 9. 何时支持服务器驱动的协商

内容协商有时也称以为conneg,是当多种资源表述形式可用时为客户端选择资源的最佳表述。尽管内容协商经常与指示媒体类型优先级相关,它也能用于指示语言本地化、字符编码和压缩编码的优先级。

HTTP指定了两种内容协商:服务器驱动协商和代理驱动协商。服务器驱动协商使用request头选择一种变体,代理驱动协商为每一种变体使用不同URI。

如何标明客户端偏好

当实现一个客户端时,对客户端来说向服务器指示自身能够处理的表述格式、语言、字符编码和压缩编码偏好和能力是非常重要的。即使能够通过带外了解响应中上诉信息,清楚指示客户端的偏好和能力有助于客户端面对变化。否则,当服务器决定提供资源的替换表述,HTTP库的任何默认偏好可能提示服务器返回了不同的表述并中断客户端。

在发送请求时,添加一个Accept头,包含逗号分隔的媒体类型优先级列表。如果媒体类型优先级不一样,对每个媒体类型添加一个q参数,以表示相关优先级(1.0~0.0,优先级越高值越大)。如果客户端仅能处理特定格式,在Accept头添加*;q=0.0以表明无法处理Accept头媒体列表之外的媒体。

如果客户端仅能处理特定字符编码,添加带有偏好字符集的Accept-Charset头,否则避免添加Accept-Charset头。为表述的偏好语言添加Accept-Language头。如果客户端能够解压缩诸如gzip、compress或deflate编码的表述,添加带有支持的压缩编码的Accept-Encoding头,否则,不要使用该头。

  1. 由于这个输出过程是由服务器决定的,所以称之为服务器驱动的内容协商。
  2. 并非所有服务器都支持q参数

如何实现媒体类型协商

如果请求中没有Accept头,那就使用默认格式来返回被请求资源的表述。

如果请求中包含Accept头,那就解析它,并按照q参数降序排序媒体类型的值。然后从此列表中选择一个服务器支持的媒体类型。在响应中包含一个Vary头。

如果所有的媒体类型服务器都不支持,那就使用后面介绍的“如何处理协商失败”中的内容来确定一个合适的响应。

如何实现语言协商

如果请求中没有Accept-Language头,那就使用默认格式来返回被请求资源的表述。

如果请求中包含Accept-Language头,那就解析它,并按照q参数降序排序语言。然后选择列表中第一个服务器所支持的语言。在响应中包含一个Vary头。

如果所有的语言服务器都不支持,并且Accept-Language头也不包含“*;q=0.0”,那就在响应中使用默认的语言。

如何实现字符编码协商

如果请求中没有Accept-Charset头,那就以UTF-8对返回的表述编码。

如果请求中包含Accept-Charset头,那就解析它,并按照q参数降序排序字符集。然后选择服务器支持的字符集。

如果所有的字符集服务器都不支持,并且Accept-Charset头也不包含“*;q=0.0”,那就在响应中使用UTF-8进行编码。

所有这些情况中,如果媒体类型是文本,且允许使用charset参数,就在Content-type中使包含charset参数,以标明服务器支持的字符编码。同样,在响应中要包含一个Vary头。

如何支持压缩

如果请求中没有Accept-Encoding头,那就不要对表述举行压缩。

如果请求中包含Accept-Encoding头,那就解析它,并按照q参数降序排序语言。然后选择列表中第一个服务器所支持的语言。在响应中包含一个Vary头。

如果所有的语言服务器都不支持,并且Accept-Encoding头也不包含“*;q=0.0”,那就忽略它。

大多数情况下,HTTP服务器可以被配置为自动为响应运用某种给定的编码。

何时及如何发送Vary头

当服务器使用内容协商来选择表述时,根据Accept-*头的不同,同一个URI可以产生不同表述。Vary头告诉客户端服务器在选择表述时使用了哪些请求头。

使用多个请求头时,请求头列表使用逗号分隔。如果服务器还使用了请求头之外的信息,如客户端的IP,当前时间,用户个性化设置等,那就将Vary头设置为*。

如何处理协商失败

如果服务器无法提供满足客户端偏好的表述,并且客户端明确包含了一个”*/*; q=0.0”,那就返回状态码406(Not Acceptable),并在表述中包含表述的列表。

如果服务器不能支持所请求的Accept-Encoding值,就不要应用任何内容编码,直接提供表述。

如何使用代理驱动的内容协商

代理驱动的协商就是为每种表述提供一个单独的URI。

代理驱动协商当客户端无法使用Accept- 头来表示偏好时很有效,它通过为每个变体提供不同URI,客户端使用URI来选择期望的表述。在代理驱动协商中,客户端通过从服务器获得的带外信息判断要使用的URI。如果表述存在,服务器返回表述,否则,返回404(Not Found)状态码。尽管所有Accept-头内要协商的信息都可在代理驱动协商中实现,通常用于媒体类型和语言类型。下面是代理驱动协商的常用做法:

  1. 查询参数,例如http://www.example.org/status?format=json和http://www.example.org/status?format=xml
  2. URI扩展,例如http://www.example.org/status.json和http://www.example.org/status.xml
  3. 子域,例如en.wikipedia.org和de.wikipedia.org

何时支持服务器驱动的协商

内容协商并不总是适合的,需要考虑Web服务支持多种格式的代价。当客户端需要多种变体或每个变体包含相同信息时,支持多种变体,否则为每个信息使用不同的URI。

在考虑为每个资源支持多种表述之前,需要考虑:

  1. 应用程序流可能对每种表述格式都不同。
  2. 内容协商仅在开发框架支持的时候代价才会很小,并不是所有代发框架都支持通过带有多个媒体类型及不同q参数的Accept头返回表述变体的。
  3. 在某些情况下,法律和商业需求可能是区域性的,代理驱动语言协商可能是更好的途径。
  4. 缓存可能无法很多好地处理内容协商响应。一些缓存可能会忽略或限制任意给定资源的存储变体个数。
文章目录
  1. 1. 如何标明客户端偏好
    1. 1.1.
  2. 2. 如何实现媒体类型协商
  3. 3. 如何实现语言协商
  4. 4. 如何实现字符编码协商
  5. 5. 如何支持压缩
  6. 6. 何时及如何发送Vary头
  7. 7. 如何处理协商失败
  8. 8. 如何使用代理驱动的内容协商
  9. 9. 何时支持服务器驱动的协商