agou专家书院 2019-06-28
Web代理(Web proxy)服务器是网络的中间实体。代理位于客户端和服务器之间,扮演"中间人"的角色,在各端点之间来回传送HTTP报文。Web上的代理服务器是代表客户端完成事务处理的中间人。如果没有Web代理,Web客户端就要直接与Web服务器进行对话。有了Web代理,客户端就可以与代理进行对话,然后由代理代表客户端与服务器进行交流。客户端仍然会完成对事务的处理,但它是通过代理服务器提供的优质服务来实现的。HTTP的代理服务器既是Web服务器又是Web客户端。Web客户端会向代理发送请求报文,代理服务器必须像Web服务器一样,正确地处理请求和连接,然后返回响应。同时,代理自身要向服务器发送请求,这样,其行为就必须像正确的Web客户端一样,要发送请求并接收响应。如果要创建自己的Web代理,就要认真地遵循为Web客户端和Web服务器制定的规则。
代理服务器可以是某个客户端专用的,也可以是很多客户端共享的。单个客户端专用的代理被称为私有代理。众多客户端共享的代理被称为公共代理。
严格来说,代理连接的是两个或多个使用相同协议的应用程序,而网关连接的则是两个或多个使用不同协议的端点。网关扮演的是"协议转换器"的角色,即使客户端和服务器使用的是不同的协议,客户端也可以通过它完成与服务器之间的事务处理。实际上,代理和网关之间的区别很模糊。由于浏览器和服务器实现的是不同版本的HTTP,代理也经常要做一些协议转换工作。而商业化的代理服务器也会实现网关的功能来支持SSL安全协议、SOCKS防火墙、FTP访问,以及基于Web的应用程序。
代理服务器可以实现各种时髦且有用的功能。它们可以改善安全性,提高性能,节省费用。代理服务器可以看到并接触到所有流过的HTTP流量,所以代理可以监视流量并对其进行修改,以实现很多有用的增值Web服务。
匿名者:匿名者代理会主动从HTTP报文中删除身份特性(比如客户端IP地址、From首部、Referer首部、cookie、URI的会话 ID),从而提供高度的私密性和匿名性。
可以根据其目标用途,将代理放在任意位置。
可以通过代理层次结构(proxy hierarchy)将代理级联起来。在代理的层次结构中,会将报文从一个代理传给另一个代理,直到最终抵达原始服务器为止(然后通过代理传回给客户端)。代理层次结构中的代理服务器被赋予了父(parent)和子(child)的关系。下一个入口(inbound)代理(靠近服务器)被称为父代理,下一个出口(outbound)代理(靠近客户端)被称为子代理。
代理服务器可以根据众多因素,将报文转发给一个不断变化的代理服务器和原始服务器集。访问代理会根据不同的情况将报文转发给父代理或原始服务器。
客户端通常会直接与Web服务器进行通信,有四种常见方式可以使客户端流量流向代理。
所有现代的Web浏览器都允许用户对代理的使用进行配置。实际上,很多浏览器都提供了多种配置代理的方式,其中包括以下几种。
PAC文件是一些小型的JavaScript程序,可以在运行过程中计算代理设置,因此,是一种更动态的代理配置解决方案。访问每个文档时,JavaScript函数都会选择恰当的代理服务器。要使用PAC文件,就要用JavaScript PAC文件的URI来配置浏览器[配置方式与手工配置类似,但要在"automatic configuration"(自动配置)框中提供一个URI]。浏览器会从这个URI上获取PAC文件,并用JavaScript逻辑为每次访问计算恰当的代理服务器。PAC文件的后缀通常是".pac",MIME类型通常是"application/x-ns- proxy-autoconfig"。每个PAC文件都必须定义一个名为"FindProxyForURL(url,host)"的函数,用来计算访问URI时使用的适当的代理服务器。
代理自动配置脚本的返回值:
"FindProxyForURL(url,host)"的返回值 | 描述 |
---|---|
DIRECT | 不经过任何代理,直接进行连接 |
PROXY host:port | 应该使用指定的代理 |
SOCKS host:port | 应该使用指定的SOCKS服务器 |
实现 WPAD 协议的客户端需要:
当前的 WPAD 协议规范按顺序定义了下列技术:
除了一点之外,Web服务器报文和Web代理报文的语法是一样的。客户端向服务器而不是代理发送请求时,HTTP请求报文中的URI会有所不同。客户端向Web服务器发送请求时,请求行中只包含部分URI(没有方案、主机或端口)。但当客户端向代理发送请求时,请求行中则包含完整的URI。</p>
<p>为什么会有两种不同的请求格式,一种用于代理,另一种用于服务器呢?在原始的HTTP设计中,客户端会直接与单个服务器进行对话。不存在虚拟主机,也没有为代理制定什么规则。单个的服务器都知道自己的主机名和端口,所以,为了避免发送冗余信息,客户端只需发送部分URI即可,无需发送方案和主机(以及端口)。代理出现之后,使用部分URI就有问题了。代理需要知道目标服务器的名称,这样它们才能建立自己与服务器的连接。基于代理的网关要知道URI的方案才能连接到FTP资源和其他方案上去。"HTTP/1.0"要求代理请求发送完整的URI,解决了这个问题,但它为服务器请求保留部分URI的形式(已经有相当多的服务器都改为支持完整URI了)。因此,我们要将部分URI发送给服务器,将完整URI发送给代理。在显式地配置客户端代理设置的情况下,客户端就知道要发布哪种类型的请求了。
代理"缺少方案/主机/端口"的问题与虚拟主机Web服务器面临的问题相同。虚拟主机Web服务器会在很多Web站点间共享同一个物理Web服务器。包含部分URI的请求到达时,虚拟主机Web服务器需要知道目的Web站点的主机名。
尽管它们出现的问题相似,但解决方法却有所不同:
只要客户端正确地实现了HTTP,它们就会在请求中包含完整的URI,发送给经过显式配置的代理。这样解决了部分问题,但还有一个问题:客户端并不总是知道它是在和代理进行对话,因为有些代理对客户端可能是不可见的。即使没有将客户端配置为使用代理,客户端的流量也可能会经过替代物或拦截代理。在这两种情况下,客户端都会认为它在与Web服务器进行对话,不会发送完整的URI。
由于将流量重定向到代理服务器的方式有所不同,通用的代理服务器既应该支持请求报文中的完整URI,也应该支持部分URI。如果是显式的代理请求,代理就应该使用完整URI,如果是Web服务器请求,就应该使用部分URI和虚拟Host首部。
使用完整和部分URI的规则如下所示。
如果提供的是部分URI,而且没有Host首部,就要用其他方法来确定原始服务器:
代理服务器要在转发报文时修改请求URI的话,需要特别小心。对URI的微小修改,甚至是看起来无害的修改,都可能给下游服务器带来一些互操作性问题。尤其是,现在已知有些代理会在将URI转发给下一跳节点之前将URI"规范"为标准格式。有些看起来无害的转换行为,比如用显式的":80"来取代默认的HTTP端口,或者用适当的换码转义符来取代非法的保留字符以校正URI,就可能造成互操作性问题。总之,代理服务器要尽量宽容一些。它们的目标不是成为强制实现严格协议一致性的"协议警察",因为这样可能会严重破坏之前能正常工作的服务。特别是,HTTP规范禁止一般的拦截代理在转发URI时重写其绝对路径部分。唯一的例外是可以用"/"来取代空路径。
根据是否有代理,浏览器对请求URI的解析会有所不同。没有代理时,浏览器会获取你输入的URI,尝试着寻找相应的IP地址。如果找到了主机名,浏览器会尝试相应的IP地址直到获得成功的连接为止。但是,如果没有找到主机,很多浏览器都会尝试着提供某种主机名自动“扩展”机制,以防用户输入的是主机“简短”的缩写形式。
现在,在将Web请求从客户端传送到服务器的路径上,经过两个或多个代理是很常见的。比如,出于安全和节省费用的考虑,很多公司都会用缓存代理服务器来访问因特网,而且很多大型ISP都会使用代理缓存来提高性能并实现各种特性。现在,有相当比例的Web请求都是通过代理转发的。同时,出于性能原因,把内容复制到遍布全球的替代物缓存库中的情形也越来越常见了。代理是由不同厂商开发的。它们有不同的特性和缺陷,由各种不同的组织负责管理。随着代理的逐渐流行,我们要能够追踪经过代理的报文流,以检测出各种问题,其重要性就跟追踪经过不同交换机和路由器传输的IP分组流一样。
Via首部字段列出了与报文途经的每个中间节点(代理或网关)有关的信息。报文每经过一个节点,都必须将这个中间节点添加到Via列表的末尾。Via首部字段用于记录报文的转发,诊断报文循环,标识请求/响应链上所有发送者的协议能力。代理也可以用Via首部来检测网络中的路由循环。代理应该在发送一条请求之前,在Via首部插入一个与其自身有关的独特字符串,并在输入的请求中查找这个字符串,以检测网络中是否存在路由循环。
Via的语法:Via首部字段包含一个由逗号分隔的路标(waypoint)。每个路标都表示一个独立的代理服务器或网关,且包含与那个中间节点的协议和地址有关的信息。
每个Via路标中最多包含4个组件:一个可选的协议名(默认为HTTP)、一个必选的协议版本、一个必选的节点名和一个可选的描述性注释。
代理服务器可以在转发报文时对其进行修改。可以添加、修改或删除首部,也可以将主体部分转换成不同的格式。代理变得越来越复杂,开发代理产品的厂商也越来越多,互操作性问题也开始逐渐显现。为了便于对代理网络进行诊断,我们需要有一种便捷的方式来观察在通过HTTP代理网络逐跳转发报文的过程中,报文是怎样变化的。通过"HTTP/1.1"的TRACE方法,用户可以跟踪经代理链传输的请求报文,观察报文经过了哪些代理,以及每个代理是如何对请求报文进行修改的。TRACE对代理流的调试非常有用。当TRACE请求到达目的服务器时,整条请求报文都会被封装在一条HTTP响应的主体中回送给发送端。当TRACE响应到达时,客户端可以检查服务器收到的确切报文,以及它所经过的代理列表(在Via首部)。TRACE响应的Content-Type为message/http,状态为"200 OK"。</p>
<p>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定义了一种名为代理认证(proxy authentication)的机制,这种机制可以阻止对内容的请求,直到用户向代理提供了有效的访问权限证书为止。若传输链路中有多个代理,且每个代理都要进行认证时,代理认证通常无法很好地工作。
客户端、服务器和代理是由不同厂商构建的,实现的是不同版本的HTTP规范。它们支持的特性各不相同,也存在着不同的问题。代理服务器位于客户端和服务器设备之间,这些设备实现的协议可能有所不同,可能存在着很棘手的问题。
代理服务器可能无法理解所有经其传输的首部字段。有些首部可能比代理自身还要新;其他首部可能是特定应用程序独有的定制首部。代理必须对不认识的首部字段进行转发,而且必须维持同名首部字段的相对顺序。类似地,如果代理不熟悉某个方法,那么只要可能,就应该尝试着将报文转发到下一跳节点上去。
通过OPTIONS方法,客户端(或代理)可以发现Web服务器或者其上某个特定资源所支持的功能(比如,它们所支持的方法)。通过使用OPTIONS,客户端可以在与服务器进行交互之前,确定服务器的能力,这样它就可以更方便地与具备不同特性的代理和服务器进行互操作了。如果OPTIONS请求的URI是个"*"(星号),请求的就是整个服务器所支持的功能。如果URI是个实际资源地址,OPTIONS请求就是在查询那个特定资源的可用特性。如果成功,OPTIONS方法就会返回一个包含了各种首部字段的"200 OK"响应,这些 字段描述了服务器所支持的,或资源可用的各种可选特性。"HTTP/1.1"在响应中唯一指定的首部字段是Allow首部,这个首部用于描述服务器所支持的各种方法(或者服务器上的特定资源)。OPTIONS允许在可选的响应主体中包含更多的信息,但并没有对这种用法进行定义。
Allow实体首部字段列出了请求URI标识的资源所支持的方法列表,如果请求URI为"*"(星号)的话,列出的就是整个服务器所支持的方法列表。可以将Allow首部作为请求首部,建议在新的资源上支持某些方法。并不要求服务器支持这些方法,但应该在相应的响应中包含一个Allow首部,列出它实际支持的方法。因为客户端可能已经通过其他途径与原始服务器进行了交流,所以即使代理无法理解指定的所有方法,也不能对Allow首部字段进行修改。