前端学HTTP之网关、隧道和中继
Web是一种强大的内容发布工具。人们已经从只在网上发送静态的在线文档,发展到共享更复杂的资源,比如数据库内容或动态生成的HTML页面。Web浏览器为用户提供了一种统一的方式来访问因特网上的内容
HTTP也已成为应用程序开发者的一种基本构造模块,开发者们可以在HTTP上梢回其他的协议内容。比如,可以将其他协议的流量包裹在HTTP中,用HTTP通过隧道或中继方式将这些流量传过公司的防火墙。Web上所有的资源都可以使用HTTP协议,而且其他应用程序和应用程序协议也可以利用HTTP来完成它们的任务
本文将详细介绍网关、隧道和中继
网关
HTTP扩展和接口的发展是由用户需求驱动的。要在Web上发布更复杂资源的需求出现时,人们很快就明确了一点:单个应用程序无法处理所有这些能想到的资源
为了解决这个问题,开发者提出了网关(gateway)的概念,网关可以作为某种翻译器使用,它抽象出了一种能够到达资源的方法。网关是资源和应用程序之间的粘合剂。应用程序可以通过HTTP或其他已定义的接口请求网关来处理某条请求,网关可以提供一条响应。网关可以向数据库发送査询语句,或者生成动态的内容,就像一个门一样:进去一条请求,出来一个响应
下图显示的是一种资源网关。在这里,Joe的服务器就是作为连接数据库内容的网关使用的——注意,客户端只是在通过HTTP请求资源,而Joe的服务器在与网关进行交互以获取资源
有些网关会自动将HTTP流量转换为其他协议,这样HTTP客户端无需了解其他协议,就可以与其他应用程序进行交互
在图a中,网关收到了对FTP URL的HTTP请求。然后网关打开FTP连接,并向FTP服务器发布适当的命令。然后将文档和正确的HTTP首部通过HTTP回送
在图b中,网关通过SSL收到了一条加密的Web请求,网关会对请求进行解 密,然后向目标服务器转发一条普通的HTTP请求。可以将这些安全加速器直接放在(通常处于同一场所的)Web服务器前面,以便为原始服务器提供髙性能的加密机制
在图c中,网关通过应用程序服务器网关API,将HTTP客户端连接到服务器端的应用程序上去。在网上的电子商店购物,査看天气预报,或者获取股票报价时,访问的就是应用程序服务器网关
Web网关在一侧使用HTTP协议,在另一侧使用另一种协议。可以用一个斜杠来分隔客户端和服务器端协议,并以此对网关进行描述:
<客户端协议>/<服务器端协议>
[注意]在不同HTTP版本之间进行转换的Web代理就像网关一样,它们会执行复杂的逻辑,以便在各个端点之间进行沟通。但因为它们在两侧使用的都是HTTP,所以从技术上来讲,它们还是代理
因此,将HTTP客户端连接到NNTP新闻服务器的网关就是一个HTTP/NNTP网关。我们用术语服务器端网关和客户端网关来说明对话是在网关的哪一侧进行的
服务器端网关(server-side gateway)通过HTTP与客户端对话,通过其他协议与服务器通信;客户端网关(client-side gateway)通过其他协议与客户端对话,通过HTTP与服务器通信
【协议网关】
将HTTP流量导向网关时所使用的方式与将流量导向代理的方式相同。最常见的方式是,显式地配置浏览器使用网关,对流量进行透明的拦截,或者将网关配置为替代者(反向代理)
1、 HTTP/*:服务器端Web网关
请求流入原始服务器时,服务器端Web网关会将客户端HTTP请求转换为其他协议
在下图中,网关收到了一条对FTP资源的HTTP请求:
ftp://ftp.irs.gov/pub/00-index.txt
网关会打开一条到原始服务器FTP端口(端口 21)的FTP连接,通过FTP协议获取对象。网关会发送USER和PASS命令登录到服务器上去;发布CWD命令,转移到服务器上合适的目录中去;将下载类型设置为ASCII;用MDTM获取文档的最后修改时间;用PASV告诉服务器将有被动数据获取请求到达;用RETR请求进行对象获取;打开到FTP服务器的数据连接,服务器端口由控制信道返回,一旦数据信道打开了,就将对象内容回送给网关
完成获取之后,会将对象放在一条HTTP响应中回送给客户端
2、HTTP/HTTPS:服务器端安全网关
一个组织可以通过网关对所有的输入Web请求加密,以提供额外的隐私和安全性保护。客户端可以用普通的HTTP浏览Web内容,但网关会自动加密用户的对话
3、HTTPS/HTTP:客户端安全加速器网关
可以将HTTPS/HTTP网关作为安全加速器使用,这些HTTPS/HTTP网关位于Web服务器之前,通常作为不可见的拦截网关或反向代理使用。它们接收安全的HTTPS流量,对安全流量进行解密,并向Web服务器发送普通的HTTP请求
这些网关中通常都包含专用的解密硬件,以比原始服务器有效得多的方式来解密安全流量,以减轻原始服务器的负荷。这些网关在网关和原始服务器之间发送的是未加密的流量。所以,要谨慎使用,确保网关和原始服务器之间的网络是安全的
【资源网关】
最常见的网关——应用程序服务器,会将目标服务器与网关结合在一个服务器中实现。应用程序服务器是服务器端网关,与客户端通过HTTP进行通信,并与服务器端的应用程序相连
在上图中,两个客户端是通过HTTP连接到应用程序服务器的。但应用程序服务器并没有回送文件,而是将请求通过一个网关应用编程接口(Application Programming Interface, API)发送给运行在服务器上的应用程序
收到客户端A的请求,根据URI将其通过API发送给一个数码相机应用程序。 将得到的图片绑定到一条HTTP响应报文中,再回送给客户端,在客户端的浏览器中显示
客户端B的URI请求的是一个电子商务应用程序。客户端B的请求是通过服务器网关API发送给电子商务软件的,结果会被回送给浏览器。电子商务软件与客户端进行交互,引导用户通过一系列HTML页面来完成购物
第一个流行的应用程序网关API就是通用网关接口(Common Gateway Interface, CGI)。CGI是一个标准接口集,Web服务器可以用它来装载程序以响应对特定URL的HTTP请求,并收集程序的输出数据,将其放在HTTP响应中回送
早期的Web服务器是相当简单的,请求需要使用网关的资源时,服务器会请辅助应用程序来处理请求。服务器会将辅助应用程序所需的数据传送给它。通常就是整条请求,或者用户想在数据库上运行的请求(来自URL的请求字符串)之类的东西
然后,它会向服务器返回一条响应或响应数据,服务器则会将其转发给客户端。服务器和网关是相互独立的应用程序,因此,它们的责任是分得很清楚
下图显示了服务器与网关应用程序之间交互的基本运行机制
这个简单的协议(输入请求,转交,响应)就是最古老,也最常用的服务器扩展接口CGI的本质
【CGI】
CGI在Web上广泛用于动态HTML,信用卡处理以及数据库査询等任务。CGI应用程序独立于服务器,所以,几乎可以用任意语言来实现,包括Perl、Tel、C和各种shell语言。CGI很简单,几乎所有的HTTP服务器都支持它
CGI的处理对用户来说是不可见的。从客户端的角度来看,就像发起一个普通请求一样。它完全不清楚服务器和CGI应用程序之间的转接过程。URL中出现字符cgi和可能出现的“?”是客户端发现使用了CGI应用程序的唯一线索
CGI在服务器和众多的资源类型之间提供了一种简单的、函数形式的粘合方式,用来处理各种需要的转换。这个接口还能很好地保护服务器,防止一些糟糕的扩展对它造成的破坏(如果这些扩展直接与服务器相连,造成的错误可能会引发服务器崩溃)
但是,这种分离会造成性能的耗费。为每条CGI请求引发一个新进程的开销是很高的,会限制那些使用CGI的服务器的性能,并且会加重服务端机器资源的负担。为了解决这个问题,人们开发了一种新型CGI——并将其恰当地称为快速CGI。这个接口模拟了CGI,但它是作为持久守护进程运行的,消除了为每个请求建立或拆除新进程所带来的性能损耗
CGI协议为外部翻译器与现有的HTTP服务器提供了一种简洁的接口方式,但如果想要改变服务器自身的行为,或者只是想尽可能地提升能从服务器上获得的性能呢?服务器开发者为这两种需求提供了几种服务器扩展API,为Web开发者提供了强大的接口,以便他们将自己的模块与HTTP服务器直接相连。扩展API允许程序员将自己的代码嫁接到服务器上,或者用自己的代码将服务器的一个组件完整地替换出来
大多数流行的服务器都会为开发者提供一个或多个扩展API。这些扩展通常都会绑定在服务器自身的结构上,所以,大多数都是某种服务器类型特有的。Apache和其他服务器都提供了一些API接口,允许开发者通过这些接口改变服务器的行为,或者为不同的资源提供一些定制的接口。这些定制接口为开发者提供了强大的接口方式
随着Web应用程序提供的服务类型越来越多,HTTP可以作为一种连接应用程序的基础软件来使用。在将应用程序连接起来的过程中,一个更为棘手的问题是在两个应用程序之间进行协议接口的协商,以便这些应用程序可以进行数据的交换——这通常都是针对具体应用程序的个案进行的
应用程序之间要配合工作,所要交互的信息比HTTP首部所能表达的信息要复杂得多。因特网委员会开发了一组允许Web应用程序之间相互通信的标准和协议。尽管Web服务(Web service)可以用来表示独立的Web应用程序(构造模块),这里我们还是宽松地用这个术语来表示这些标准。Web服务的引入并不新鲜,但这是应用程序共享信息的一种新机制。Web服务是构建在标准的Web技术(比如HTTP)之上的
Web服务可以用XML通过SOAP来交换信息。XML(Extensible Markup Language, 扩展标记语言)提供了一种创建数据对象的定制信息,并对其进行解释的方法。SOAP(Simple Object Access Protocol,简单对象访问协议)是向HTTP报文中添加XML信息的标准方式
隧道
Web隧道(Web tunnel)是HTTP的另一种用法,可以通过HTTP应用程序访问使用非HTTP协议的应用程序。Web隧道允许用户通过HTTP连接发送非HTTP流量,这样就可以在HTTP上捎带其他协议数据了。使用Web隧道最常见的原因就是要在HTTP连接中嵌入非HTTP流量,这样,这类流量就可以穿过只允许Web流量通过的防火墙了
【建立隧道】
Web隧道是用HTTP的CONNECT方法建立起来的。CONNECT方法请求隧道网关创建一条到达任意目的服务器和端口的TCP连接,并对客户端和服务器之间的后继数据进行盲转发
下图显示了CONNECT方法如何建立起一条到达网关的隧道
在图a中,客户端发送了一条CONNECT请求给隧道网关。客户端的CONNECT方法请求隧道网关打开一条TCP连接(在这里,打开的是到主机orders.joes-hardware.com的标准SSL端口443的连接);在图b和图c中创建了TCP连接;一旦建立了TCP连接,网关就会发送一条HTTP 200 Connection Established响应来通知客户端;此时,隧道就建立起来了。客户端通过HTTP隧道发送的所有数据都会被直接转发给输出TCP连接,服务器发送的所有数据都会通过HTTP隧道转发给客户端
上图中的例子描述了一条SSL隧道,其中的SSL流量是在一条HTTP连接上发送的,但是通过CONNECT方法可以与使用任意协议的任意服务器建立TCP连接
1、CONNECT请求
除了起始行之外,CONNECT的语法与其他HTTP方法类似。一个后面跟着冒号和端口号的主机名取代了请求URI。主机和端口都必须指定:
CONNECT home.netscape.com:443 HTTP/1.0 User-agent: Mozilla/4.0
和其他HTTP报文一样,起始行之后,有零个或多个HTTP请求首部字段。这些行照例以CRLF结尾,首部列表以一个空的CRLF结束
2、CONNECT响应
发送了请求之后,客户端会等待来自网关的响应。和普通HTTP报文一样,响应码200表示成功。按照惯例,响应中的原因短语通常被设置为“Connection Established”
HTTP/1.0 200 Connection Established Proxy-agent: Netscape-Proxy/1.1
与普通HTTP响应不同,这个响应并不需要包含Content-Type首部。此时连接只是对原始字节进行转接,不再是报文的承载者,所以不需要使用内容类型
管道化数据对网关是不透明的,所以网关不能对分组的顺序和分组流作任何假设。一旦隧道建立起来了,数据就可以在任意时间流向任意方向了
作为一种性能优化方法,允许客户端在发送了CONNECT请求之后,接收响应之前,发送隧道数据。这样可以更快地将数据发送给服务器,但这就意味着网关必须能够正确处理跟在请求之后的数据。尤其是,网关不能假设网络I/O请求只会返回首部数据,网关必须确保在连接准备就绪时,将与首部一同读进来的数据发送给服务器。在请求之后以管道方式发送数据的客户端,如果发现回送的响应是认证请求,或者其他非200但不致命的错误状态,就必须做好重发请求数据的准备。如果在任意时刻,隧道的任意一个端点断开了连接,那个端点发出的所有未传输数据都会被传送给另一个端点,之后,到另一个端点的连接也会被代理终止。如果还有数据要传输给关闭连接的端点,数据会被丢弃
【SSL隧道】
最初开发Web隧道是为了通过防火墙来传输加密的SSL流量。很多组织都会将所有流量通过分组过滤路由器和代理服务器以隧道方式传输,以提升安全性。但有些协议,比如加密SSL,其信息是加密的,无法通过传统的代理服务器转发。隧道会通过一条HTTP连接来传输SSL流置,以穿过端口80的HTTP防火墙
为了让SSL流量经现存的代理防火墙进行传输,HTTP中添加了一项隧道特性,在此特性中,可以将原始的加密数据放在HTTP报文中,通过普通的HTTP信道传送
在图a中,SSL流量被直接发送给了一个(SSL端口443上的)安全Web服务器。在图b中,SSL流量被封装到一条HTTP报文中,并通过HTTP端口80上的连接发送,最后被解封装为普通的SSL连接
通常会用隧道将非HTTP流量传过端口过滤防火墙。这一点可以得到很好的利用。比如,通过防火墙传输安全SSL流量。但是,这项特性可能会被滥用,使得恶意协议通过HTTP隧道流入某个组织内部
可以像其他协议一样,对HTTPS协议(SSL上的HTTP)进行网关操作:由网关(而不是客户端)初始化与远端HTTPS服务器的SSL会话,然后代表客户端执行 HTTPS事务。响应会由代理接收并解密,然后通过(不安全的)HTTP传送给客户端。这是网关处理FTP的方式。但这种方式有几个缺点:客户端到网关之间的连接是普通的非安全HTTP;尽管代理是已认证主体,但客户端无法对远端服务器执行SSL客户端认证(基于X509证书的认证);网关要支持完整的SSL实现
对于SSL隧道机制来说,无需在代理中实现SSL。SSL会话是建立在产生请求的客户端和目的(安全的)Web服务器之间的,中间的代理服务器只是将加密数据经过隧道传输,并不会在安全事务中扮演其他的角色
在适当的情况下,也可以将HTTP的其他特性与隧道配合使用。尤其是,可以将代理的认证支持与隧道配合使用,对客户端使用隧道的权利进行认证
总的来说,隧道网关无法验证目前使用的协议是否就是它原本打算经过隧道传输的协议。因此,比如说,一些喜欢捣乱的用户可能会通过本打算用于SSL的隧道,越过公司防火墙传递因特网游戏流量,而恶意用户可能会用隧道打开Telnet会话,或用隧道绕过公司的E-mail扫描器来发送E-mail。为了降低对隧道的滥用,网关应该只为特定的知名端口,比如HTTPS的端口443打开隧道
中继
中继(relay)是没有完全遵循HTTP规范的简单HTTP代理。中继负责处理HTTP中建立连接的部分,然后对字节进行盲转发
HTTP很复杂,所以实现基本的代理功能并对流量进行盲转发,而且不执行任何首部和方法逻辑,有时是很有用的。盲中继很容易实现,所以有时会提供简单的过滤、诊断或内容转换功能。但这种方式可能潜在严重的互操作问题,所以部署的时候要特别小心
某些简单盲中继实现中存在的一个更常见(也更声名狼藉的)问题是,由于它们无法正确处理Connection首部,所以有潜在的挂起keep-alive连接的可能
在图a中,Web客户端向中继发送了一条包含Connection: Keep-Alive首部的报文,如果可能的话要求建立一条keep-alive连接。客户端等待响应,以确定它要求建立keep-alive信道的请求是否被认可了
中继收到了这条HTTP请求,但它并不理解Connection首部,因此会将报文一字不漏地沿着链路传递给服务器。但Connection首部是个逐跳首部,只适用于单条传输链路,是不应该沿着链路传送下去的
在图b中,经过中继转发的HTTP请求抵达Web服务器。当Web服务器收到经过代理转发的Connection: Keep-Alive首部时,会错误地认为中继(对服务器来说,它看起来就和其他客户端一样)要求进行keep-alive的对话。这对Web服务器来说没什么问题——它同意进行keep-alive对话,并在图c中回送了一个Connection: Keep-Alive响应首部。此时,Web服务器就认为它是在与中继进行keep-alive对话,会遵循keep-alive对话的规则。但中继对keep-alive会话根本就一无所知
在图d中,中继将Web服务器的响应报文,以及来自Web服务器的Connection: Keep-Alive首部一起发回给客户端。客户端看到这个首部,认为中继同意进行keep-alive对话。此时,客户端和服务器都认为它们是在进行keep-alive对话,但与它们进行对话的中继却根本不知道什么keep-alive对话
中继对持久对话一无所知,所以它会将收到的所有数据都转发给客户端,等待原始服务器关闭连接。但原始服务器认为中继要求服务器将连接保持在活跃状态,所以是不会关闭连接的。这样,中继就会挂起,等待连接的关闭
在图d中,当客户端收到回送的响应报文时,它会直接转向第二条请求,在 keep-alive连接上向中继发送另一条请求。简单中继通常不会期待同一条连接上还会有另一条请求到达。浏览器上的圈会不停地转,但没有任何进展
有一些方法可以使中继稍微智能一些,以消除这些风险,但所有简化的代理都存在着出现互操作性问题的风险。要为某个特定目标构建简单的HTTP中继,一定要特别注意其使用方法。对任何大规模部署来说,都要非常认真地考虑使用真正的、完全遵循HTTP的代理服务器