HTTP(六)代理

私有和共享代理

代理服务器可以是某个客户端专用的,也可以是很多客户端共享的。单个客户端专用的代理被称为私有代理。众多客户端共享的代理被称为公共代理。

  • 公共代理
    大多数代理都是公共的共享代理。集中式代理的成本效率更高,更容易管理。某些代理应用,比如高速缓存代理服务器,会利用用户间共同的请求,这样的话,汇入同一个代理服务器的用户越多,它就越有用。
  • 私有代理

    专用的私有代理并不常见,但它们确实存在,尤其是直接运行在客户端计算机上的时候。有些浏览器辅助产品,以及一些ISP 服务,会在用户的PC 上直接运行一些小型的代理,以便扩展浏览器特性,提高性能,或为免费ISP 服务提供主机广告。

代理与网关的对比

严格来说,代理连接的是两个或多个使用相同协议的应用程序,而网关连接的则是两个或多个使用不同协议的端点。网关扮演的是“协议转换器”的角色,即使客户端和服务器使用的是不同的协议,客户端也可以通过它完成与服务器之间的事务处理。

实际上,代理和网关之间的区别很模糊。由于浏览器和服务器实现的是不同版本的HTTP,代理也经常要做一些协议转换工作。而商业化的代理服务器也会实现网关的功能来支持SSL 安全协议、SOCKS 防火墙、FTP 访问,以及基于Web 的应用程序。

为什么使用代理

代理服务器可以实现各种时髦且有用的功能。它们可以改善安全性,提高性能,节省费用。代理服务器可以看到并接触到所有流过的HTTP 流量,所以代理可以监视流量并对其进行修改,以实现很多有用的增值Web 服务。这里给出了几种代理使用方法的示例。

  • 儿童过滤器
    小学在为教育站点提供无阻碍访问的同时,可以利用过滤器代理来阻止学生访问成人内容。代理应该允许学生无限制地访问教育性内容,但对不适合儿童的站点要强行禁止访问
  • 文档访问控制
    可以用代理服务器在大量Web 服务器和Web 资源之间实现统一的访问控制策略,创建审核跟踪机制。这在大型企业环境或其他分布式机构中是很有用的。
  • 安全防火墙
    网络安全工程师通常会使用代理服务器来提高安全性。代理服务器会在网络中的单一安全节点上限制哪些应用层协议的数据可以流入或流出一个组织。还可以提供用来消除病毒的Web 和E-mail 代理使用的那种挂钩程序,以便对流量进行详细的检查
  • Web 缓存
    代理缓存维护了常用文档的本地副本,并将它们按需提供,以减少缓慢且昂贵的因特网通信。
  • 反向代理
    代理可以假扮Web 服务器。这些被称为替代物(surrogate)或反向代理(reverseproxy)的代理接收发给Web 服务器的真实请求,但与Web 服务器不同的是,它们可以发起与其他服务器的通信,以便按需定位所请求的内容。可以用这些反向代理来提高访问慢速Web 服务器上公共内容时的性能。在这种配置中,通常将这些反向代理称为服务器加速器(server accelerator)。
  • 内容路由器
    代理服务器可以作为“内容路由器”使用,根据因特网流量状况以及内容类型将请求导向特定的Web 服务器。
  • 转码器
    代理服务器在将内容发送给客户端之前,可以修改内容的主体格式。在这些数据表示法之间进行的透明转换被称为转码(transcoding)。
  • 匿名者
    匿名者代理会主动从HTTP 报文中删除身份特性(比如客户端IP 地址、From首部、Referer 首部、cookie、URI 的会话ID),从而提供高度的私密性和匿名性。

代理会去往何处

代理服务器的部署

  • 出口代理
    可以将代理固定在本地网络的出口点,以便控制本地网络与大型因特网之间的流量。可以在公司网络中使用出口代理,提供针对公司外部恶意黑客的防火墙保护,或降低带宽费用,提高因特网流量的性能。小学可能会使用过滤出口代理来防止早熟的学生浏览不恰当的内容。
  • 访问(入口)代理
    代理常被放在ISP 访问点上,用以处理来自客户的聚合请求。ISP 使用缓存代理来存储常用文档的副本,以提高用户(尤其是高速连接用户)的下载速度,降低因特网带宽耗费。
  • 反向代理
    代理通常会被部署在网络边缘,在Web 服务器之前,作为替代物(也常被称为反向代理)使用,在那里它们可以处理所有传送给Web 服务器的请求,并只在必要时向Web 服务器请求资源。替代物可以提高Web 服务器的安全特性,或者将快速的Web 服务器缓存放在较慢的服务器之前,以提高性能。反向代理通常会直接冒用Web 服务器的名字和IP 地址,这样所有的请求就会被发送给代理而不是服务器了。
  • 网络交换代理
    可以将具有足够处理能力的代理放在网络之间的因特网对等交换点上,通过缓存来减轻因特网节点的拥塞,并对流量进行监视

代理的层次结构

可以通过代理层次结构(proxy hierarchy)将代理级联起来。在代理的层次结构中,会将报文从一个代理传给另一个代理,直到最终抵达原始服务器为止(然后通过代理传回给客户端)。

Proxy 层次结构中的代理服务器被赋予了父(parent)和子(child)的关系。下一个入口(inbound)代理(靠近服务器)被称为父代理,下一个出口(outbound)代理(靠近客户端)被称为子代理。

代理层次结构的内容路由

上图中的代理层次结构是静态的——代理1 总是会将报文转发给代理2,代理2总是会将报文转发给代理3。但是,层次不一定非得是静态的。代理服务器可以根据众多因素,将报文转发给一个不断变化的代理服务器和原始服务器集。

这里还有几个动态选择父代理的例子。

  • 负载均衡

    子代理可能会根据当前父代理上的工作负载级别来决定如何选择一个父代理,以均衡负载。

  • 地理位置附近的路由
    子代理可能会选择负责原始服务器所在物理区域的父代理。
  • 协议 / 类型路由
    子代理可能会根据URI 将报文转发到不同的父代理和原始服务器上去。某些特定类型的URI 可能要通过一些特殊的代理服务器转发请求,以便进行特殊的协议处理。
  • 基于订购的路由
    如果发布者为高性能服务额外付费了,它们的URI 就会被转发到大型缓存或压缩引擎上去,以提高性能。

代理是如何获取流量的

客户端通常会直接与Web 服务器进行通信,所以我们要解释清楚HTTP 流量怎样才能首先流向代理。有四种常见方式可以使客户端流量流向代理。

  • 修改客户端
    很多Web 客户端,包括网景和微软的浏览器,都支持手工和自动的代理配置。如果将客户端配置为使用代理服务器,客户端就会将HTTP 请求有意地直接发送给代理,而不是原始服务器
  • 修改网络
    网络基础设施可以通过若干种技术手段,在客户端不知道,或没有参与的情况下,拦截网络流量并将其导入代理。这种拦截通常都依赖于监视HTTP 流量的交换设备及路由设备,在客户端毫不知情的情况下,对其进行拦截,并将流量导入一个代理。这种代理被称为拦截(intercepting)代理。
  • 修改 DNS 的命名空间
    放在Web 服务器之前的代理服务器——替代物,会直接假扮Web 服务器的名字和IP 地址,这样,所有的请求就会发送给这些替代物,而不是服务器了。要实现这一点,可以手工编辑DNS 名称列表,或者用特殊的动态DNS 服务器根据需要来确定适当的代理或服务器。有时在安装过程中,真实服务器的IP 地址和名称被修改了,替代物得到的会是之前的地址和名称。
  • 修改 Web 服务器
    也可以将某些Web 服务器配置为向客户端发送一条HTTP 重定向命令(响应码305),将客户端请求重定向到一个代理上去。收到重定向命令后,客户端会与代理进行通信

客户端的代理设置

所有现代的Web 浏览器都允许用户对代理的使用进行配置。

  • 手工配置
    显式地设置要使用的代理。
  • 预先配置浏览器
    浏览器厂商或发行商会在将浏览器发送给其客户之前预先对浏览器(或所有其他Web 客户端)的代理设置进行手工配置。
  • 代理的自动配置(Proxy Auto-Configuration,PAC)
    提供一个URI,指向一个用JavaScript 语言编写的代理自动配置文件;客户端会取回这个JavaScript 文件,并运行它以决定是否应该使用一个代理,如果是的话,应该使用哪个代理服务器。
  • WPAD 的代理发现
    有些浏览器支持Web 代理自动发现协议(Web Proxy Autodiscovery Protocol,WPAD),这个协议会自动检测出浏览器可以从哪个“配置服务器”下载到一个自动配置文件

客户端的代理配置:手工配置

其他浏览器都有不同的方式来进行手工配置的修改,但其思想是一样的:为代理指定主机和端口。有些ISP 会向客户发送预先配置好的浏览器,或定制好的操作系统,使其将Web 流量重定向到代理服务器上。

客户端代理配置:PAC文件

PAC 文件是一些小型的JavaScript 程序,可以在运行过程中计算代理设置,因此,是一种更动态的代理配置解决方案。访问每个文档时,JavaScript 函数都会选择恰当的代理服务器。

要使用PAC 文件,就要用JavaScript PAC 文件的URI 来配置浏览器[配置方式与手工配置类似,但要在 “automatic configuration”(自动配置)框中提供一个URI]。浏览器会从这个URI 上获取PAC 文件,并用JavaScript 逻辑为每次访问计算恰当的代理服务器。PAC 文件的后缀通常是.pac,MIME 类型通常是application/x-nsproxy-autoconfig。

每个PAC 文件都必须定义一个名为FindProxyForURL(url,host) 的函数,用来计算访问URI 时使用的适当的代理服务器。

function FindProxyForURL(url, host) {
  if (url.substring(0,5) == "http:") {
    return "PROXY http-proxy.mydomain.com:8080";
  } else if (url.substring(0,4) =="ftp:") {
    return "PROXY ftp-proxy.mydomain.com:8080";
  } else {
    return "DIRECT";
  }
}

客户端代理配置:WPAD

另一种浏览器配置机制是WPAD 协议。WPAD 协议的算法会使用发现机制的逐级上升策略自动地为浏览器查找合适的PAC 文件。实现WPAD 协议的客户端需要:

  • 用 WPAD 找到 PAC 的 URI;
  • 从指定的 URI 获取 PAC 文件;
  • 执行 PAC 文件来判定代理服务器;
  • 为请求使用代理服务器。

当前的WPAD 协议规范按顺序定义了下列技术:

  • 动态主机配置协议(Dynamic Host Configuration Protocol,DHCP);
  • 服务定位协议(Service Location Protocol,SLP);
  • DNS 知名主机名;
  • DNS SRV 记录;
  • TXT 记录中的 DNS 服务 URI。

与代理请求有关的一些棘手问题

代理URI与服务器URI的不同

Web 服务器报文和Web 代理报文的语法是一样的。只是报文中的URI 会有所不同。

客户端向Web 服务器发送请求时,请求行中只包含部分URI(没有方案、主机或端口)

GET /index.html HTTP/1.0
User-Agent: SuperBrowser v1.3

但当客户端向代理发送请求时,请求行中则包含完整的URI。

GET http://www.marys-antiques.com/index.html HTTP/1.0
User-Agent: SuperBrowser v1.3

为什么会有两种不同的请求格式,一种用于代理,另一种用于服务器呢?在原始的HTTP 设计中,客户端会直接与单个服务器进行对话。不存在虚拟主机,也没有为代理制定什么规则。单个的服务器都知道自己的主机名和端口,所以,为了避免发送冗余信息,客户端只需发送部分URI 即可,无需发送方案和主机(以及端口)。代理出现之后,使用部分URI 就有问题了。代理需要知道目标服务器的名称,这样它们才能建立自己与服务器的连接。基于代理的网关要知道URI 的方案才能连接到FTP 资源和其他方案上去。HTTP/1.0 要求代理请求发送完整的URI,解决了这个问题,但它为服务器请求保留部分URI 的形式(已经有相当多的服务器都改为支持完整URI 了)。

我们要将部分URI 发送给服务器,将完整URI 发送给代理。在显式地配置客户端代理设置的情况下,客户端就知道要发布哪种类型的请求了。

与虚拟主机一样的问题

代理“缺少方案/ 主机/ 端口”的问题与虚拟主机Web 服务器面临的问题相同。虚拟主机Web 服务器会在很多Web 站点间共享同一个物理Web 服务器。包含部分URI(比如/index.html)的请求到达时,虚拟主机Web 服务器需要知道目的Web 站点的主机名。

尽管它们出现的问题相似,但解决方法却有所不同:

  • 显式的代理要求在• 请求报文中使用完整 URI 来解决这个问题;
  • 虚拟主机 Web 服务器要求使用 Host 首部来承载主机和端口信息。

注: 现在,HTTP/1.1 要求服务器为代理请求和服务器请求都提供完整的URI 处理,但实际上,很多已部署的服务器仍然只接受部分URI。

拦截代理会收到部分URI

只要客户端正确地实现了HTTP,它们就会在请求中包含完整的URI,发送给经过显式配置的代理。这样解决了部分问题,但还有一个问题:客户端并不总是知道它是在和代理进行对话,因为有些代理对客户端可能是不可见的。即使没有将客户端配置为使用代理,客户端的流量也可能会经过替代物或拦截代理。在这两种情况下,客户端都会认为它在与Web 服务器进行对话,不会发送完整的URI。

如前所述,反向代理是一个用来取代原始服务器的代理服务器,它通常会通过假扮服务器的主机名或IP 地址来做到这一点。它会收到Web 服务器请求,可能会向真正的服务器提供缓存的响应或者代理请求。客户端无法区分反向代理和Web服务器,因此它会发送部分URI

拦截代理是网络流量中的代理服务器,它会拦截从客户端发往服务器的请求,并提供一个缓存响应,或对其进行转发。由于拦截代理拦截了从客户端到服务器的流量,所以它会收到发送给Web 服务器的部分URI

注意:

  • 正向代理:服务器端不知道具体的客户端是谁,例如,vpn
  • 反向代理:客户端不知道具体的服务器端是谁,例如,负载均衡的方案

代理既可以处理代理请求,也可以处理服务器请求

由于将流量重定向到代理服务器的方式有所不同,通用的代理服务器既应该支持请求报文中的完整URI,也应该支持部分URI。如果是显式的代理请求,代理就应该使用完整URI,如果是Web 服务器请求,就应该使用部分URI 和虚拟Host 首部。

  • 如果提供的是完整 URI,代理就应该使用这个完整 URI。
  • 如果提供的是部分 URI,而且有 Host 首部,就应该用 Host 首部来确定原始服务器的名字和端口号。

  • 如果提供的是部分URI,而且没有Host首部,就要用其他方法来确定原始服务器
    如果代理是代表原始服务器的替代物,可以用真实服务器的地址和端口号来配置代理;
    如果流量被拦截了,而且拦截者也可以提供原始的 IP 地址和端口,代理就可以使用拦截技术提供的IP 地址和端口号
    如果所有方法都失败了,代理没有足够的信息来确定原始服务器,就必须返回一条错误报文(通常是建议用户升级到支持Host 首部的现代浏览器)

转发过程中对URI的修改

代理服务器要在转发报文时修改请求URI 的话,需要特别小心。对URI 的微小修改,甚至是看起来无害的修改,都可能给下游服务器带来一些互操作性问题。尤其是,现在已知有些代理会在将URI 转发给下一跳节点之前将URI“规范”为标准格式。有些看起来无害的转换行为,比如用显式的“:80”来取代默认的HTTP 端口,或者用适当的换码转义符来取代非法的保留字符以校正URI,就可能造成互操作性问题。
总之,代理服务器要尽量宽容一些。它们的目标不是成为强制实现严格协议一致性的“协议警察”,因为这样可能会严重破坏之前能正常工作的服务。特别是,HTTP 规范禁止一般的拦截代理在转发URI 时重写其绝对路径部分。唯一的例外是可以用“/”来取代空路径。

URI的客户端自动扩展和主机名解析

根据是否有代理,浏览器对请求URI 的解析会有所不同。没有代理时,浏览器会获取你输入的URI,尝试着寻找相应的IP 地址。如果找到了主机名,浏览器会尝试相应的IP 地址直到获得成功的连接为止。
但是,如果没有找到主机,很多浏览器都会尝试着提供某种主机名自动“扩展”机制,以防用户输入的是主机“简短”的缩写形式

  • 很多浏览器会尝试着加入前缀www. 和• 后缀 .com,以防用户只输入了常见 Web站点名的中间部分(比如,人们可以输入yahoo 而不是www.yahoo.com)

  • 有些浏览器甚至会将未解析出来的 URI 传递给第三方站点,这个站点会尝试着校正拼写错误,并给出一些用户可能希望访问的URI 建议。

  • 而且,大多数系统中的 DNS 配置允许用户只输入主机名的前缀,然后 DNS 会自动搜索域名。如果用户位于域名oreilly.com 的范围之内,并输入了主机名host7,DNS 会自动尝试将其与host7.oreilly.com 进行匹配。这并不是完整有效的主机名。

没有代理时URI的解析

没有提供显式的代理时,浏览器会对部分主机名进行自动扩展

有显式代理时URI的解析

使用显式代理时,用户的URI 会被直接发送给代理,所以浏览器就不再执行所有这些便捷的扩展功能了。

有显式代理时,浏览器没有对不完整的主机名进行自动扩展。因此,当用户在浏览器的地址窗口中输入oreilly 时,发送给代理的就是http://oreilly/(浏览器添加了默认方案和路径,但主机名和输入的一样)。

因此,有些代理会尽力尝试着去模仿浏览器的便捷服务,包括www...com 自动扩展,以及添加本地域名后缀

有拦截代理时URI的解析

使用不可见的拦截代理时,对主机名的解析会略有不同,因为对客户端来说,是没有代理的!这种情况下的行为与使用服务器的情形很类似,浏览器会自动扩展主机名,直到DNS 成功为止。但如图所示,建立到服务器的连接时,有一个很重要的区别。

  • 在第(1) 步中,用户在浏览• 器的 URI 地址窗口中输入 oreilly。
  • 在第 (2a) 步中,浏览器通过 DNS 查找主机 oreilly,但 DNS 服务器失败了,并回送响应说明主机未知,如第(2b) 步所示。

  • 在第 (3a) 步中,浏览器进行了自动扩展,将 oreilly 转换成 www.oreilly.com。在第(3b) 步中,浏览器通过DNS 来查找主机www.oreilly.com。这一次,如第(3c)步所示,DNS 服务器成功了,将IP 地址返回给了浏览器。

  • 在第 (4a) 步中,客户端已经成功解析了主机名,并有了一张 IP 地址列表。有些IP 地址可能已经停用了,所以,通常客户端会尝试着连接每个IP 地址,直到成功为止。但对拦截代理来说,第一次连接请求就会被代理服务器拦截成功,不会连接到原始服务器上去。客户端认为它在与Web 服务器进行成功的对话,但那个Web 服务器可能甚至都不处于活跃状态。

  • 当代理最终准备好与真正的原始服务器进行交互时[第 (5b) 步],代理可能会发现那个IP 地址实际指向的是一个已停用的服务器。为了提供与浏览器相同级别的容错机制,代理可以通过解析Host 首部的主机名,也可以通过对IP 地址的反向DNS 查找来尝试其他IP 地址。将浏览器配置为使用显式代理时,它们会依赖代理的容错机制,所以对拦截和显式的代理实现来说,在DNS 解析到已停用服务器时,提供容错机制是很重要的。

追踪报文

现在,在将Web 请求从客户端传送到服务器的路径上,经过两个或多个代理是很常见的。比如,出于安全和节省费用的考虑,很多公司都会用缓存代理服务器来访问因特网, 而且很多大型ISP 都会使用代理缓存来提高性能并实现各种特性。现在,有相当比例的Web 请求都是通过代理转发的。同时,出于性能原因,把内容复制到遍布全球的替代物缓存库中的情形也越来越常见了。

Via首部

Via 首部字段列出了与报文途经的每个中间节点(代理或网关)有关的信息。报文每经过一个节点,都必须将这个中间节点添加到Via 列表的末尾。

下面的Via 字符串告诉我们报文流经了两个代理。这个字符串说明第一个代理名为proxy-62.irenes-isp.net, 它实现了HTTP/1.1 协议, 第二个代理被称为cache.joes-hardware.com,实现了HTTP/1.0:

Via: 1.1 proxy-62.irenes-isp.net, 1.0 cache.joes-hardware.com

Via 首部字段用于记录报文的转发,诊断报文循环,标识请求/ 响应链上所有发送者的协议能力

代理也可以用Via 首部来检测网络中的路由循环。代理应该在发送一条请求之前,在Via 首部插入一个与其自身有关的独特字符串,并在输入的请求中查找这个字符串,以检测网络中是否存在路由循环。

1. Via的语法

Via 首部字段包含一个由逗号分隔的路标(waypoint)。每个路标都表示一个独立的代理服务器或网关,且包含与那个中间节点的协议和地址有关的信息。下面是一个带有两个路标的Via 首部实例:

Via = 1.1 cache.joes-hardware.com, 1.1 proxy.irenes-isp.net

Via 首部的正规语法如下所示:

Via = "Via" ":" 1#( waypoint )
waypoint = ( received-protocol received-by [ comment ] )
received-protocol = [ protocol-name "/" ] protocol-version
received-by = ( host [ ":" port ] ) | pseudonym

注意,每个Via 路标中最多包含4 个组件:一个可选的协议名(默认为HTTP)、一个必选的协议版本、一个必选的节点名和一个可选的描述性注释。

  • 协议名
    中间节点收到的协议。如果协议为HTTP 的话,协议名就是可选的。否则,要在版本之前加上协议名,中间用“/”分隔。网关将HTTP 请求连接到其他协议(HTTPS、FTP 等)时,可能会使用非HTTP 协议。
  • 协议版本
    所收到的报文版本。版本的格式与协议有关。HTTP 使用的是标准版本号(1.0、1.1 等)。版本包含在Via 字段中,这样,之后的应用程序就会知道前面所有中间节点的协议能力了。
  • 节点名
    中间节点的主机和可选端口号(如果没有包含端口号,可以假定使用的是协议的默认端口号)。在某些情况下,出于隐私方面的考虑,某个组织可能不愿意给出真实的主机名,在这种情况下可以用一个假名来代替。
  • 节点注释
    进一步描述这个中间节点的可选注释。通常会在这里包含厂商和版本信息,有些代理服务器还会在注释字段中包含一些与此设备上所发生事件有关的诊断信息。

2. Via的请求和响应路径

请求和响应报文都会经过代理进行传输,因此,请求和响应报文中都要有Via首部。
请求和响应通常都是通过同一条TCP 连接传送的,所以响应报文会沿着与请求报文相同的路径回传。如果一条请求报文经过了代理A、B 和C,相应的响应报文就会通过代理C、B、A 进行传输。因此,响应的Via 首部基本上总是与请求的Via 首部相反

3. Via与网关

有些代理会为使用非HTTP 协议的服务器提供网关的功能。Via 首部记录了这些协议转换,这样,HTTP 应用程序就会了解代理链上各点的协议处理能力以及所做的协议转换了。图显示了一个通过HTTP/FTP 网关请求某个FTP URI 的HTTP客户端。

4. Server和Via首部

Server 响应首部字段对原始服务器使用的软件进行了描述。这里有几个例子:

Server: Apache/1.3.14 (Unix) PHP/4.0.4
Server: Netscape-Enterprise/4.1
Server: Microsoft-IIS/5.0

如果响应报文是通过代理转发的,一定要确保代理没有修改Server 首部。Server首部是用于原始服务器的。代理应该添加的是Via 条目。

5. Via的隐私和安全问题

有时候,我们并不希望在Via 字符串中使用确切的主机名。总地来说,除非显式地允许了这种行为,否则,当代理服务器作为网络防火墙的一部分使用时,是不应该转发防火墙后面那些主机的名字和端口号的,因为防火墙后面的网络结构信息可能会被恶意群体利用。
如果不允许进行Via 节点名转发,作为安全防线的一部分使用的代理就应该用适当的假名来取代那台主机的名字。一般来说,即使隐藏了真实名称,代理也应该尝试着为每台代理服务器保留一个Via 路标条目。

对那些有着非常强烈的隐私要求,需要隐藏内部网络设计和拓扑结构的组织来说,代理应该将一个(接收协议值相同的)有序Via 路标条目序列合并成一个联合条目。比如,可以将:

Via: 1.0 foo, 1.1 devirus.company.com, 1.1 access-logger.company.com

压缩成:

Via: 1.0 foo, 1.1 concealed-stuff

TRACE方法

代理服务器可以在转发报文时对其进行修改。可以添加、修改或删除首部,也可以将主体部分转换成不同的格式。代理变得越来越复杂,开发代理产品的厂商也越来越多,互操作性问题也开始逐渐显现。为了便于对代理网络进行诊断,我们需要有一种便捷的方式来观察在通过HTTP 代理网络逐跳转发报文的过程中,报文是怎样变化的。通过HTTP/1.1 的TRACE 方法,用户可以跟踪经代理链传输的请求报文,观察报文经过了哪些代理,以及每个代理是如何对请求报文进行修改的。TRACE 对代理流的调试非常有用。

当TRACE 请求到达目的服务器时,16 整条请求报文都会被封装在一条HTTP 响应的主体中回送给发送端。当TRACE 响应到达时,客户端可以检查服务器收到的确切报文,以及它所经过的代理列表(在Via 首部)。TRACE 响应的Content-Type 为message/http,状态为200 OK。

Max-Forwards

通常,不管中间插入了多少代理,TRACE 报文都会沿着整条路径传到目的服务器上。可以使用Max-Forwards(最大转发次数)首部来限制TRACE 和OPTIONS请求所经过的代理跳数,在测试代理链是否是在无限循环中转发报文,或者查看链中特定代理服务器的效果时,它是很有用的。Max-Forwards 也可以限制OPTIONS报文的转发。

Max-Forwards 请求首部字段包含了一个整数,用来说明这条请求报文还可以被转发的次数)。如果Max-Forwards 的值为零(Max-Forwards:0),那么即使接收者不是原始服务器,它也必须将TRACE 报文回送给客户端,而不应该继续转发。

如果收到的Max-Forwards 值大于零, 转发的报文中就必须包含一个更新了的Max-Forwards 字段, 其值会被减一。所有的代理和网关都应该支持Max-Forwards。可以用Max-Forwards 来查看在代理链的任意一跳上接收到的请求。

代理认证

代理可以作为访问控制设备使用。HTTP 定义了一种名为代理认证(proxyauthentication)的机制,这种机制可以阻止对内容的请求,直到用户向代理提供了有效的访问权限证书为止。

  • 对受限内容的请求到达一台代理服务器时,代理服务器可以返回一个要求使用访问证书的407 Proxy Authorization Required 状态码,以及一个用于描述怎样提供这些证书的Proxy-Authenticate 首部字段

  • 客户端收到 407 响应时,会尝试着从本地数据库中,或者通过提示用户来搜集所需要的证书。

  • 只要获得了证书,客户端就会重新发送请求,在 Proxy-Authorization 首部字段中提供所要求的证书。

  • 如果证书有效,代理就会将原始请求沿着传输链路向下传送;否则,就发送另一条407 应答。

若传输链路中有多个代理,且每个代理都要进行认证时,代理认证通常无法很好地工作。人们建议,应该对HTTP 进行升级,将认证证书与代理链中特定的路标联系起来,但这些升级措施并没有得到广泛实现。

代理的互操作性

客户端、服务器和代理是由不同厂商构建的,实现的是不同版本的HTTP 规范。它们支持的特性各不相同,也存在着不同的问题。代理服务器位于客户端和服务器设备之间,这些设备实现的协议可能有所不同,可能存在着很棘手的问题。

处理代理不支持的首部和方法

代理服务器可能无法理解所有经其传输的首部字段。有些首部可能比代理自身还要新;其他首部可能是特定应用程序独有的定制首部。代理必须对不认识的首部字段进行转发,而且必须维持同名首部字段的相对顺序。 类似地,如果代理不熟悉某个方法,那么只要可能,就应该尝试着将报文转发到下一跳节点上去。在当今的大部分网络中,如果代理不能转发它不支持的方法,可能就无法生存下去了,因为通过微软的Outlook 进行Hotmail 访问就大量地使用了HTTP 扩展方法。

OPTIONS:发现对可选特性的支持

通过HTTP OPTIONS 方法,客户端(或代理)可以发现Web 服务器或者其上某个特定资源所支持的功能(比如,它们所支持的方法)。通过使用OPTIONS,客户端可以在与服务器进行交互之前,确定服务器的能力,这样它就可以更方便地与具备不同特性的代理和服务器进行互操作了。

如果OPTIONS 请求的URI 是个星号(*),请求的就是整个服务器所支持的功能。比如:

OPTIONS * HTTP/1.1

如果URI 是个实际资源地址,OPTIONS 请求就是在查询那个特定资源的可用特性:

OPTIONS http://www.joes-hardware.com/index.html HTTP/1.1

如果成功,OPTIONS 方法就会返回一个包含了各种首部字段的200 OK 响应,这些字段描述了服务器所支持的,或资源可用的各种可选特性。HTTP/1.1 在响应中唯一指定的首部字段是Allow 首部,这个首部用于描述服务器所支持的各种方法(或者服务器上的特定资源)。OPTIONS 允许在可选的响应主体中包含更多的信息,但并没有对这种用法进行定义。

Allow首部

Allow 实体首部字段列出了请求URI 标识的资源所支持的方法列表,如果请求URI为* 的话,列出的就是整个服务器所支持的方法列表。

Allow: GET, HEAD, PUT

可以将Allow 首部作为请求首部,建议在新的资源上支持某些方法。并不要求服务器支持这些方法,但应该在相应的响应中包含一个Allow 首部,列出它实际支持的方法。
因为客户端可能已经通过其他途径与原始服务器进行了交流,所以即使代理无法理解指定的所有方法,也不能对Allow 首部字段进行修改。

posted @ 2018-01-14 16:54  hahazexia  阅读(384)  评论(0)    收藏  举报