随着最近WebSocket服务器实现的高速增长,对于HTML5 Web Socket如何处理代理服务器,防火墙,以及负载平衡路由器出现了许多疑问。代理服务器是否会自动中断WebSocket连接?HTML5 Web Sockets是否能比Comet更好的处理防火墙与代理服务器问题呢?Web Sockets又是否是实行无缝的代理服务器遍历的银弹呢?在这篇文章中,我将会解释HTML5 Web Sockets是如何与代理服务器,负载平衡路由器以及防火墙进行交互的。此外,我将会解释Kazzing WebSocket网关及其Web Socket模仿功能如何带来额外的价值。
关于HTML5 Web Sockets与代理服务器
让我们从一些基本概念开始:HTML5 Web Sockets和代理服务器究竟是什么?
HTML5 Web Sockets
HTML5 Web Sockets规范定义了Web Sockets API,支持页面使用Web Socket协议与远程主机进行全双工的通信。它引入了WebSocket接口并且定义了一个全双工的通信通道,通过一个单一的套接字在Web上进行操作。HTML5 Web Sockets以最小的开销高效地提供了Web连接。相较于经常需要使用推送实时数据到客户端甚至通过维护两个HTTP连接来模拟全双工连接的旧的轮询或长轮询(Comet)来说,这就极大的减少了不必要的网络流量与延迟。
要使用HTML5 Web Sockets从一个Web客户端连接到一个远程端点,你要创建一个新的WebSocket实例并为之提供一个URL来表示你想要连接到的远程端点。该规范定义了ws://
以及wss://
模式来分别表示WebSocket和安全WebSocket连接。一个WebSocket连接是在客户端与服务器之间HTTP协议的初始握手阶段将其升级到Web Socket协议来建立的,其底层仍是TCP/IP连接。
Proxy Servers
一个代理服务器是作为客户端与另一个服务器之间的一个中介(比如,因特网上的一个web服务器)。代理服务器通常被用作内容缓存,因特网连接,安全,以及企业内容过滤。典型的,一个代理服务器被架设在私有网络与因特网之间。代理服务器可以监控流量并断开连接,如果该连接已打开很久。对于使用长期活跃连接的web应用来说(比如,Comet HTTP流或者HTML5 Web Sockets),代理服务器的问题是明显的:HTTP代理服务器——原本最初设计用来文档转移——可能会选择关闭流或闲置的WebSocket连接,因为它们看起好像是尝试连接一个没有回应的HTTP服务器。这一行为对于长久的连接,比如WebSockets来说,是存在问题的。另外,代理服务器可能会缓冲未加密的HTTP响应,这将会对HTTP响应流带来不可估计的延迟。
HTML5 Web Sockets和代理服务器
让我们看看HTML5 Web Sockets是如何与代理服务器工作的。WebSocket连接使用标准HTTP端口(80和443),这让很多人管它叫做“代理服务器和防火墙友好协议”。因此,HTML5 Web Sockets不需要安装新的硬件,或者要求公司网络开放新的端口——这两件事足以使任何新的协议夭折。在浏览器与WebSocket服务器之间不需要任何中间服务器(代理或反向代理服务器,防火墙,负载平衡路由器等等),只要服务器和客户端双方都理解Web Socket协议,WebSocket连接就可以顺利的建立。然而,在真实的环境中,许多网络流量都被路由到中间服务器。
一图胜千言。图1展示了一个简化的网络拓扑,客户端使用浏览器来访问后端基于TCP的服务,这里使用了全双工的HTML5 WebSocket连接。一些客户端位于公司网络内部,受到公司防火墙的保护,并被配置为通过显式的或者已知的代理服务器来访问因特网,这些代理服务器会提供内容缓存和安全;而其它的客户端则直接在因特网上访问WebSocket。两种情况中,客户端的请求都可能被路由到透明的,或者未知的代理服务器(例如,一个数据中心的代理服务器或者远程服务器前端的一个反向代理服务器)。代理服务器甚至还有可能有它们自己的显式的代理服务器,这又增加了WebSocket传输需要的中继数。
图1——有着显式和透明的代理服务器的Web Sockets架构
跟常规的使用请求/响应协议的HTTP传输不一样,WebSocket连接可以长时间保持打开。代理服务器也许可以支持这点并优雅地处理,但它们同时也可能带来破坏因素。
WebSocket Upgrade
HTML5 Web Sockets使用HTTP Upgrade机制升级到Web Socket协议。HTML5 Web Sockets有着兼容HTTP的握手机制,因此HTTP服务器可以与WebSocket服务器共享默认的HTTP与HTTPS端(80和443)。要建立一个WebSocket连接,客户端和服务器在初次握手的时候从HTTP协议提升到Web Socket协议,如例1所展示的。一旦连接建立,WebSocket数据帧就可以以全双工的模式在客户端和服务器之间来回传输。
例1—WebSocket升级握手
客户端到服务器:
GET /demo HTTP/1.1 Upgrade: WebSocket Connection: Upgrade Host: example.com Origin: http://example.com WebSocket-Protocol: sample
服务器到客户端:
HTTP/1.1 101 Web Socket Protocol Handshake Upgrade: WebSocket Connection: Upgrade WebSocket-Origin: http://example.com WebSocket-Location: ws://example.com/demo WebSocket-Protocol: sample
未加密的WebSocket连接
Web Socket协议本身并不知道代理服务器与防火墙;它只定义了WebSocket升级握手与WebSocket数据帧的格式。让我们看看在两种代理服务器场景(显式的和透明的)中未加密WebSocket传输的情况。
未加密WebSocket连接与显式代理服务器
如果一个浏览器被配置为使用显式的代理服务器,那么在建立WebSocket连接时它首先向代理服务器发出HTTP CONNECT
方法。比如,要使用ws://
模式(通常是通过80端口)连接到服务器example.com,浏览器客户端就会像例2所示的那样向代理服务器发出HTTP CONNECT
方法。
例2—使用80端口的HTTP CONNECT
方法
CONNECT example.com:80 HTTP/1.1 Host: example.com
当这个显式的代理服务器允许CONNECT
方法时,WebSocket连接升级握手得以完成,握手成功后,WebSocket信息流就可以畅通无阻地通过代理服务器传输了。
未加密的WebSocket连接与透明代理服务器
如果是未加密的WebSocket信息流通过透明的代理传输到WebSocket服务器这种情况,实践中连接很可能失败,因为在这种情况下,浏览器没有发出CONNECT
方法。当代理服务器将请求转发到(WebSocket)服务器时,将会被剥去一些特定的消息头,包括Connection消息头。因此,一个工作良好的透明代理服务器几乎会立刻引起WebSocekt升级握手失败。
并非所有的代理服务器在所期待的代理行为方面都遵循HTTP标准。比如,一些代理服务器被配置为不删除Connection: Upgrade
消息头,并将其传送给WebSocket服务器,反过来服务器又会发送101 Web Socket Protocol Handshake响应。而当客户端或服务器开始发送第一个WebSocket帧时问题就出现了。因为这帧数据与代理服务器所期待的任何事物(比如常规的HTTP流量)都不相同,就可能会产生一些异常,除非代理服务器被特别配置为处理WebSocket流量。
逐跳升级
在WebSocket的握手阶段,Connection: Upgrade
消息头被发送给WebSocket服务器。如果代理服务器不得不参与进升级机制的话,额外的代理服务器就必不可少,因为使用了逐跳传送;从代理服务器发送到浏览器的升级只适用于一跳,而代理服务器必须发送它自己的升级消息头来处理从代理服务器到WebSocket服务器(或另一个中间服务器)的下一跳。同时代理服务器还必须停止按HTTP来处理该请求。
目前,大部分透明代理服务器都还不了解Web Socket协议,而这些代理服务器也无法支持Web Socket协议。然而,未来,代理服务器将会是Web Socket可知的,并且能够合理的处理与转发WebSocket信息流。
加密的WebSocket连接
现在,让我们来看看加密的WebSocket信息流在两种不同的代理服务器场景下的情况(显式的和透明的)。
加密的WebSocket连接与显式的代理服务器
如果一个浏览器被配置为使用显式的代理服务器,那么在建立WebSocket连接时它首先会向该代理服务器发出一个HTTP CONNECT
方法。比如,要使用wss://
模式(典型地是通过443端口),连接到服务器example.com,浏览器客户端会发送如例3所示的HTTP CONNECT
方法到代理服务器。
例3——使用端口443的HTTP CONNECT
方法
CONNECT example.com:443 HTTP/1.1 Host: example.com
当显式的代理服务器允许CONNECT
方法时,TLS握手被发送出去,后面紧跟着WebSocket连接升级握手。这系列的握手成功后,WebSocket信息流就可以开始无阻碍的通过代理服务器了。HTTPS(HTTP over TLS)也是以同样的方式工作的;使用加密通常会触发HTTP CONNECT
方法。
加密的WebSocket连接与透明的代理服务器
如果是透明代理服务器的情况,浏览器不知道代理服务器,因此不会有HTTP CONNECT
方法被发送。然而,因为线上信息是加密的,中间的透明代理服务器可能会简单的让加密的信息通过。因此,如果使用了Web Sockets安全的话,WebSocket连接成功的几率要大得多。因此,始终与TLS加密一起使用Web Sockets安全来连接到WebSocket服务器是最佳的做法,除非你非常确实不会存在中间服务器。虽然这样做的好处是带来了更好的安全,但TLS加密确实会增加客户端与服务器两方面的CPU消耗,尽管这并非是特别大的增加,而且通过硬件的SSL/TLS加速,可以将其减小到几乎可忽略。
让我们再重述一下要点。图2展示了在浏览器与WebSocket服务器之间建立WebSocket连接过程中所做的决定。这张图展示了在WebSocket(ws://
)与WebSocket安全(wss://
)两种情况中使用显式的和透明的代理服务器建立连接的不同场景。
图2——代理服务器遍历决策树
图2显示了在几乎是最简单的网络拓扑中为什么使用未加密的WebSocket连接更容易失败。所有都归结到要理解你所要部署WebSocket应用的端到端网络拓扑。一些HTTP代理服务器也许会限制端口或者只允许特定的被授权的服务器来访问。在这种场景中使用的WebSocket服务器必须被加入到服务器白名单中,连接才有可能成功。 通常,应当使用哪个协议(ws://
或是wss://
)来进行连接的是由客户端开发者来决定,同时还需要基于WebSocket信息流的隐私特征。未来,WebSocket网关和服务器能够支持在探测到不合作的代理服务器时,动态地升级到Web Socket安全。
Kaazing WebSocket网关和代理服务器
Kaazing WebSocket网关的特色功能有Web Socket模拟,以支持Web Socket对所有浏览器可用,包括那些不支持Web Sockets的。这一模拟工作在纯粹的JavaScript环境,不需要插件,同时还有Kazzing独家的Opportunistic Optimization™技术可以保证最佳的连接环境,无论客户端与中间代理服务器是否支持最新的协议。
例如:如果Kaazing WebSocket网关探测到存在Flash插件,客户端类库可以充分利用单一的(Flash)TCP套接字连接的优势,并且,如果直接连接无法实现(例如,如果通讯必须经过防火墙或者一个HTTP代理服务器),那么客户端类库仍然可以利用Flash运行时的优势,最小化客户端的内存剖析。
如果中间代理服务器位于Kaazing WebSocket网关与客户端的中间,那么就会使用一个高度优化的加密流式连接,并且代理-服务器-感知的网关会自动的转发HTTP请求,以使用加密的HTTP(HTTPS)连接来让流式特性的下行HTTP信息流忽略代理服务器。在生产环境中,需要预先考虑到HTTPS流可以被用作最坏情况的场景下,以留有一步余地。然而,为了使起动作起来,网关必须被配置适用于TLS加密的证书。如果没有的话(这会被视为一个配置错误),Kaazing将会退回到一种高级的非流式的实现。
kaazing的Web Socket模拟是高度优化的,并且轻而易举的就可以超越大部分的遗留Comet解决方案,因为它通过退回到HTTPS流保证了最小的延迟,这得归功于Kazzing底层对于跨不同源的HTTP和HTTPS请求的支持。注意不同的退回场景仅被用于模拟模式。使用Kaazing WebSocket网关及其Web Socket模拟的一个主要好处就是你现在就可以按照HTML5 Web Sockets标准来编码,并且这些应用可以运行于所有的浏览器。
负载平衡路由器与防火墙
这一节描述了HTML5 Web Socket是如何与负载平衡路由器和防火墙一起工作的。另外,还解释了Kaazing WebSocket网关如何带到额外的价值。
HTML5 Web Sockets与负载平衡路由器
对于这一讨论,让我们首先分清两种不同类型的负载平衡路由器:
Ø TCP(第4层)负载平衡路由器以与HTML5 Web Sockets很好的工作,因为他们有同样的连接形式:一开始连接一次并保持连接,而不是HTTP文档转移的请求——响应式的形式。
Ø HTTP(第7层)负载平衡路由器它本是为HTTP信息流准备的,因此很容易就会被WebSocket升级信息流所迷惑。因此,第7层负载平衡路由器需要被配置为能明确感知WebSocket信息流。
HTML5 Web Sockets与防火墙
因为防火墙通常是在对进入的流量控制和出去的流量路由上加上规则(比如,通过代理服务器)因此通常来说没有对于WebSocket信息流相关的防火墙顾虑。
kaazing Websocket网关与负载均衡路由器
第7层负载均衡路由器被置于浏览器与多个WebSocket服务器之间的关键路径时,有可能会被WebSocket协议升级请求搞糊涂。出于这个目的,运行于Kaazing WebSocket网关的服务支持伙伴负载均衡器感知,这允许负载均衡路由器被配置为WebSocket服务器的伙伴。通过这种方式,负载均衡路由器只需要处理初始的客户端请求并可以发现最佳的活动网关实例来路由信息。
一旦负载均衡路由器选择了网关实例,该网关实例就可以将浏览器转接,直接连接到该活动的网关实例。这意味着负载均衡路由器不介入真正的WebSocket流量,由此减少了延迟。然而,出现了硬件失效或网络错误的时候,客户端会自动重连到负载均衡路由器,这将会自动的将那些请求转发到另一个活动的kaazing网关实例。
Comet与代理服务器
最后,让我们来看看Comet是如何与代理服务器交互的。因为不存在Comet的标准,让我们区别来看两种不同类型的Comet实现:长轮询与流式查询。
Ø 长轮询,其实现方式健壮,不会受代理服务器问题的太大影响,因为它仅仅使用HTTP请求响应模型。然而,每个请求和响应载体会有许多不必要的HTTP头信息开销和延迟。这正是HTML5 Web Sockets大展身手的地方——它能够提供1000:1的降低不必要的网络流量和延迟。
同时请查阅:我们的桔皮书《Web Sockets——Web伸缩性的量变飞跃 》,其中对于Web Sockets较遗留的Comet解决方案所能带来的显著减少不必要的网络流量提供了详尽的分析。
Ø 流式查询通常比长轮询更高效,因为它在服务器上保持响应开放,并只将关键的数据通过开放连接发送给客户端。然而,这一方案会受到之前提到的代理服务器问题的影响。比如,一个代理服务器可能会缓冲响应而造成延迟。作为替代,代理服务器可以被配置为断开保持了一定时间的HTTP连接。这也是为什么大多数遗留Comet解决方案简单的使用长轮询的原因。
总结
尽管HTML5 Web Socket协议本身并不知晓代理服务器和防火墙,但它具有HTTP兼容的握手这一特色,因此HTTP服务器可以和WebSocket服务器共享它们默认的HTTP和HTTPS端口(80和443)。一些代理服务器于Web Sockets无害并且能很好的工作,其它一些有可能妨碍Web Sockets正常工作,导致连接失败。在一些情况下可能需要一些额外的代理服务器配置,而一些特定的代理服务器可能需要被升级以支持Web Sockets。
如果一个浏览器被配置为使用显式的代理服务器(对于加密和未加密的WebSocket连接都是),那么在建立WebSocket连接时它首先会发出一个HTTP CONNECT
方法到那个代理服务器。
如果使用的是一个未加密的WebSocket连接(ws://
),那么在透明的代理服务器情况下,浏览器是不知道代理服务器的,所以不会发送HTTP CONNECT
方法。因此,在目前的实践中连接通常会失败。
如果使用的是加密的WebSocket安全连接(wss://
),那么在透明代理服务器下,浏览器不知道代理服务器,所以不会发出 HTTP CONNECT
方法。然而,因为线上信息是加密的,中间透明代理服务器会简单的让加密信息通过,因此使用加密的WebSocket连接而成功建立WebSocket连接的几率就大大增加了。
kaazing WebSocket网关是高度优化的,代理感知的WebSocket网关,提供原生的WebSocket支持和针对上一代浏览器的Web Socket模拟功能。如果中间代理服务器被检测到,那么下行HTTP信息流就会使用一个高度优化的加密流式连接。这是通过Kaazing底层通过跨源的HTTP和HTTPS请求支持来实现的。在这一方面,不管是原生的或模拟的方式,我们可以通过WebSocket网关100%的建立WebSocket连接。
关于作者
Peter Lubbers是Kaazing的文档和培训主管,掌控文档和培训工作的各个方面,Peter是Apress出版的《Pro HTML5 Programming》的合著者并教授HTML5培训课程。是HTML5和WebSocket的热衷者,他经常在国际活动上公开演讲。
在加入Kaazing之前,Peter是Oracle的一名信息架构师,他编写了多本书箱,包括获奖的Oracle应用服务器门户配置手册,以及Oracle应用服务器微软Office交互开发者指南。Peter同时还开发文档自动化解决方案,并获得了两项发明专利。
在加入Oracle之前,Peter架构并开发了国际化的微软Office运用专家测试框架。Peter同时还是《Pro JSF and Ajax: Building Rich Internet Components》(Apress,2006)这本书的技术审稿人。