17.1 内容协商技术

来源:互联网 发布:android精彩编程200例 编辑:程序博客网 时间:2024/05/22 13:17
  • 同一个 URL 针对不同用户提供不同的资源。比如给英语用户发送英文页面,给中文用户发送中文页面,但用户访问的是同一个 URL。
  • HTTP 提供了内容协商方法,允许客户端和服务器作这样的决定。通过这些方法,单一的 URL 就可以代表不同的资源,这些不同的版本称为变体。
  • 对于特定的 URL 来说,服务器还可以根据其他原则来决定发送什么内容给客户端最合适。在有些场合下,服务器甚至可以自动生成定制的页面。比如,服务器可以为手持设备把 HTML 页面转换成 WML 页面。这类动态内容变换被称为转码。这些变换动作是 HTTP 客户端和服务器之间进行内容协商的结果。
  • 内容协商技术:共 3 种,让客户端来选择、服务器自动判定、让中间代理来选,分别称为客户端驱动的协商、服务器驱动的协商以及透明协商:
    这里写图片描述

1. 客户端驱动的协商

  • 对于服务器来说,收到客户端请求时只是发回响应,在其中列出可用的页面,让客户端决定要看哪个,这是最容易的事情。很显然,这是服务器最容易实现的方式,而且客户端很可能选择到最佳的版本(只要列表中有让客户端选择的足够信息)。
  • 不利之处是每个页面都需要两次请求:第一次获取列表,第二次获取选择的副本。这种技术速度很慢且过程枯燥乏味,让用户厌烦。
  • 从实现原理上来说,服务器实际上有两种方法为客户端提供选项:
    • 一是发送回一个 HTML 文档,里面有到该页面的各种版本的链接和每个版本的描述信息;客户端浏览器收到这种响应时,会显示一个带有链接的页面。
    • 另一种方法是发送回 HTTP/1.1 响应时,使用 300 Multiple Choices 响应代码;客户端浏览器收到这种响应时,可能会弹出对话窗口,让用户做选择。
    • 不管怎么样,决定是由客户端的浏览器用户作出的。
  • 这种方法还有一个缺点:它需要多个 URL,公共页面要一个,其他每种特殊页面也都要一个。

2. 服务器驱动的协商

  • 减少额外通信量的一种方法是让服务器来决定发送哪个页面回去,但为了做到这一点,客户端必须发送有关客户偏好的足够信息,以便服务器能够作出准确的决策。服务器通过客户端请求的首部集来获得这方面的信息。
  • 有以下两种机制可供 HTTP 服务器评估发送什么响应给客户端比较合适:
    • 检查内容协商首部集。服务器察看客户端发送的 Accept 首部集,设法用相应的响应首部与之匹配。
    • 根据其他(非内容协商)首部进行变通。例如,服务器可以根据客户端发送的 User-Agent 首部来发送响应。

1. 内容协商首部集

  • 客户端可以用下表列出的 HTTP 首部集发送用户的偏好信息:
首部 描述 Accept 告知服务器发送何种媒体类型 Accept-Language 告知服务器发送何种语言 Accept-Charset 告知服务器发送何种字符集 Accept-Encoding 告知服务器采用何种编码
  • 注意,这些首部与第 15 章讨论的那些实体首部非常类似。不过,这两种首部的用途截然不同:
    • 实体首部集像运输标签,它们描述了把报文从服务器传输给客户端的过程中必须的各种报文主体属性。
    • 内容协商首部集是由客户端发送给服务器用于交换偏好信息的,以便服务器可以从文档的不同版本中选择出最符合客户端偏好的那个来提供服务。
Accept 首部 实体首部 Accept Content-Type Accept-Language Content-Language Accept-Charset Content-Type Accept-Encoding Content-Encoding
  • 注意,由于 HTTP 是无状态的协议(表示服务器不会在不同的请求之间追踪客户端的偏好),所以客户端必须在每个请求中都发送其偏好信息。

2. 内容协商首部中的质量值

  • HTTP 协议中定义了质量值(简称 q 值),允许客户端为每种偏好类别列出多种选项,并为每种偏好选项关联一个优先次序。
    Accept-Language: en;q=0.5, fr;q=0.0, nl;q=1.0, tr;q=0.0
    其中 q 值的范围从 0.0 ~ 1.0(0.0 是优先级最低的,而 1.0 是优先级最高的)。
    注意,偏好的排列顺序并不重要,只有与偏好相关的 q 值才是重要的。
  • 服务器偶尔也会碰到找不到文档可以匹配客户端的任何偏好的情况。对于这种情况,服务器可以修改文档,也就是对文档进行转码,以匹配客户端的偏好。

3. 随其他首部集而变化

  • 服务器也可以根据其他客户端请求首部集来匹配响应,比如 User-Agent 首部。例如,服务器知道老版本的浏览器不支持 JavaScript 语言,这样就可以向其发送不含有 JavaScript 的页面版本。
  • 在这种情况下,没有 q 值机制可供查找“最近似”的匹配。服务器或者去找完全匹配,或者简单地有什么就给什么,这取决于服务器的实现。
  • 由于缓存需要尽力提供所缓存文档中正确的“最佳”版本,HTTP 协议定义了服务器在响应中发送的 Vary 首部。这个首部告知缓存(还有客户端和所有下游的代理)服务器根据哪些首部来决定发送响应的最佳版本。

4. Apache 中的内容协商

  • 下面概括了著名的 Web 服务器 Apache 是如何支持内容协商的。网站的内容提供者,比如说 Joe,要负责为 Joe 的索引页面提供不同的版本。Joe 还必须把这些索引页面文件放在和站点相关的 Apache 服务器的适当目录下。用以下两种方式可以启用内容协商:
    • 在网站目录中,为网站中每个有变体的 URI 创建一个 type-map(类型映射)文件。这个 type-map 文件列出了每个变体和其相关的内容协商首部集。
    • 启用 MultiViews 指令,这样会使 Apache 自动为目录创建 type-map 文件。

1. 使用 type-map 文件

  • Apache 服务器需要知道 type-map 文件的命名规则。可以在服务器的配置文件中设置 handler 来说明 type-map 文件的后缀名。例如:
    AddHandler type-map .var
    这行就说明了后缀是 .var 的文件就是 type-map 文件。
  • 这里给出一个 type-map 文件示例:
URI: joes-hardware.htmlURI: joes-hardware.en.htmlContent-type: text/htmlContent-language: enURI: joes-hardware.fr.de.html Content-type: text/html;charset=iso-8859-2 Content-language: fr, de
  • 根据这个 type-map 文件,Apache 服务器就知道要发送 joes-hardware.en.html 给请求英语版的客户端,发送 joes-hardware.fr.de.html 给请求法语版的客户端。Apache 服务器也支持质量值,具体信息请参阅它的文档。

2. 使用MultiView

  • 为了使用 MultiView,必须在网站目录下的 access.conf 文件中的适当小节(、 Location>,或 )使用 OPTION 指令来启用它。
  • 如果启用了 MultiView,而浏览器又请求了名为 joes-hardware 的资源,服务器就会查找所有名字中含有 joes-hardware 的文件,并为它们创建 type-map 文件。服务器会根据名字猜测其对应的内容协商首部集。例如,法语版的 joes-hardware 应当含有 .fr。

5. 服务器端扩展

  • 另一种在服务器端实现内容协商的方法是使用服务器端扩展,比如微软的动态服务器页面(Microsoft’s Active Server Pages,ASP)。

3. 透明协商

  • 透明协商机制试图从服务器上去除服务器驱动协商所需的负载,并用中间代理来代表客户端以使与客户端的报文交换最小化。假定代理了解客户端的预期,这样就可以代表客户端与服务器协商(在客户端请求内容的时候,代理已经收到了客户端的预期)。
  • 为了支持透明内容协商,服务器必须有能力告知代理,服务器需要检查哪些请求首部,以便对客户端的请求进行最佳匹配。HTTP/1.1 规范中没有定义任何透明协商机制,但定义了 Vary 首部。服务器在响应中发送了 Vary 首部,以告知中间节点需要使用哪些请求首部进行内容协商。
  • 代理缓存可以为通过单个 URL 访问的文档保存不同的副本。如果服务器把它们的决策过程传给缓存,这些代理就能代表服务器与客户端进行协商。缓存同时也是进行内容转码的好地方,因为部署在缓存里的通用转码器能对任意服务器,而不仅仅是一台服务器传来的内容进行转码。

1. 进行缓存与备用候选

  • 对内容进行缓存的时候是假设内容以后还可以重用。然而,为了确保对客户端请求回送的是正确的已缓存响应,缓存必须应用服务器在回送响应时所用到的大部分决策逻辑。
  • 之前描述了客户端发送的 Accept 首部集,以及为了给每条请求选择最佳的响应,服务器使用的与这些首部集匹配的相应实体首部集。缓存也必须使用相同的首部集来决定回送哪个已缓存的响应。
  • 下图展示了涉及缓存的正确及错误的操作序列。缓存把第一个请求转发给服务器,并存储其响应。对于第二个请求,缓存根据 URL 查找到了匹配的文档。但是,这份文档是法语版的,而请求者想要的是西班牙语版的。如果缓存只是把文档的法语版本发给请求者的话,它就犯了错误。因此,缓存也应该把第二条请求转发给服务器,并保存该 URL 的响应与“备用候选”响应。缓存现在就保存了同一个 URL 的两份不同的文档,与服务器上一样。这些不同的版本称为变体(variant)或备用候选(alternate)。内容协商可看成是为客户端请求选择最合适变体的过程。
    这里写图片描述

2. Vary 首部

  • 如果服务器的决策不是依据 Accept 首部集,而是比如 User-Agent 首部的话,缓存必须知道这些首部是什么,这样才能在选择回送的页面时做出同样的逻辑判断。
  • HTTP 的 Vary 响应首部中列出了所有客户端请求首部,服务器可用这些首部来选择文档或产生定制的内容(在常规的内容协商首部集之外的内容)。例如,若所提供的文档取决于 User-Agent 首部,Vary 首部就必须包含 User-Agent。
  • 当新的请求到达时,缓存会根据内容协商首部集来寻找最佳匹配。但在把文档提供给客户端之前,它必须检查服务器有没有在已缓存响应中发送 Vary 首部。如果有 Vary 首部,那么新请求中那些首部的值必须与旧的已缓存请求里相应的首部相同。因为服务器可能会根据客户端请求的首部来改变响应,为了实现透明协商,缓存必须为每个已缓存变体保存客户端请求首部和相应的服务器响应首部。
    这里写图片描述
  • 如果某服务器的 Vary 首部看起来像下面这样,大量不同的 User-Agent 和 Cookie 值将会产生非常多的变体:
    Vary: User-Agent, Cookie
  • 缓存必须为每个变体保存其相应的文档版本。当缓存执行查找时,首先会对内容协商首部集进行内容匹配,然后比较请求的变体与缓存的变体。如果无法匹配,缓存就从原始服务器获取文档。
原创粉丝点击