The WebSocket协议支持创建可在客户端与服务器之间进行实时双向通信的Web应用。作为HTML5的一部分,WebSocket让此类应用的开发比以往的方法更加容易。大多数现代浏览器都支持WebSocket,包括Chrome、Firefox、Internet Explorer、Opera和Safari;同时,支持WebSocket的服务器应用框架也越来越多。
对于企业生产环境,如果需要使用多台WebSocket服务器来保障性能和高可用性,则需要一个能够识别WebSocket协议的负载均衡层。NGINX从1.3版起便支持WebSocket,可充当反向代理,并对WebSocket应用进行负载均衡。(所有版本的NGINX Plus也都支持WebSocket。)
查看近期的性能测试,了解NGINX对WebSocket连接进行负载均衡时的可扩展性。
WebSocket协议与HTTP协议不同,但WebSocket握手与HTTP兼容,可通过HTTP Upgrade机制将连接从HTTP升级为WebSocket。这样,WebSocket应用可以更轻松地融入现有基础设施。例如,WebSocket应用可以使用标准HTTP端口80和443,从而沿用现有的防火墙规则。
WebSocket应用会在客户端与服务器之间保持长时间连接,从而便于开发实时应用。用于将连接从HTTP升级到WebSocket的HTTP Upgrade机制使用Upgrade和Connection标头。反向代理服务器在支持WebSocket时会面临一些挑战。其中之一是WebSocket采用逐跳协议,因此,当代理服务器拦截来自客户端的Upgrade请求时,需要向后端服务器发送自己的Upgrade请求,并包含相应的标头。此外,与HTTP通常使用的短连接不同,WebSocket连接会长期保持,因此反向代理需要允许这些连接保持打开状态,而不能因为连接看似空闲就将其关闭。
NGINX支持WebSocket,可在客户端与后端服务器之间建立隧道。要让NGINX将客户端的Upgrade请求发送到后端服务器,必须显式设置Upgrade和Connection标头,如下例所示:
location /wsapp/ { proxy_pass http://wsbackend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header Host $host;
}完成此配置后,NGINX会将其作为WebSocket连接处理。
NGINX WebSocket 示例
以下实时示例展示了NGINX如何作为WebSocket代理运行。此示例使用ws,这是一个基于Node.js构建的WebSocket实现。NGINX充当反向代理,为一个使用ws和Node.js的简单WebSocket应用提供代理服务。这些说明已在Ubuntu 13.10和CentOS 6.5上通过测试,但对于其他操作系统和版本,可能需要进行调整。在此示例中,WebSocket服务器的IP地址为192.168.100.10,NGINX服务器的IP地址为192.168.100.20。
- 如果尚未安装Node.js和npm,请运行以下命令:
- 对于Debian和Ubuntu:
$ sudo apt-get install nodejs npm- 对于RHEL和CentOS:
$ sudo yum install nodejs npm- 在Ubuntu上,Node.js安装为
nodejs;在CentOS上,则安装为node。本示例使用node,因此需要在Ubuntu上创建一个从nodejs指向node的符号链接:
$ ln -s /usr/bin/nodejs /usr/local/bin/node- 要安装ws,请运行以下命令:
$ sudo npm install ws- 注意:如果收到错误消息“Error: failed to fetch from registry: ws”,请运行以下命令解决此问题:
$ sudo npm config set registry http://registry.npmjs.org/- 然后再次运行
sudo npm install ws命令。 - ws附带程序/root/node_modules/ws/bin/wscat,我们将使用该程序作为客户端,但还需要创建一个程序作为服务器。创建名为server.js的文件,内容如下:
console.log("Server started");
var Msg = '';
var WebSocketServer = require('ws').Server
, wss = new WebSocketServer({port: 8010});
wss.on('connection', function(ws) {
ws.on('message', function(message) {
console.log('Received from client: %s', message);
ws.send('Server received from client: ' + message);
});
});- 要执行服务器程序,请运行以下命令:
$ node server.js- 服务器首先输出一条
"Serverstarted"消息,然后侦听端口 8010,等待客户端连接。收到客户端请求后,服务器会回显该请求,并向客户端发回一条包含所接收消息的消息。为使 NGINX 代理这些请求,我们创建以下配置。我们添加map块,以便在请求中的Connection标头设置为close时,将Upgrade标头正确设置为''。
http {
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
upstream websocket {
server 192.168.100.10:8010;
}
server {
listen 8020;
location / {
proxy_pass http://websocket;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $host;
}
}
}- NGINX监听端口8020,并将请求代理到后端WebSocket服务器。
proxy_set_header指令使NGINX能够正确处理WebSocket协议。 - 为测试服务器,我们运行wscat作为客户端:
$ /root/node_modules/ws/bin/wscat --connect ws://192.168.100.20:8020- wscat通过NGINX代理连接到WebSocket服务器。在wscat中输入要发送到服务器的消息后,可以看到该消息显示在服务器上,随后服务器发出的消息会显示在客户端上。以下是交互示例:服务器:客户端:
$node server.js服务器已启动
wscat --connect ws://192.168.100.20:8020
已连接(按CTRL+C退出)
> Hello从客户端收到:Hello< 服务器从客户端收到:Hello由此可见,客户端和服务器能够通过作为代理的NGINX进行通信,并可持续双向发送消息,直到客户端或服务器断开连接。要让NGINX正确处理WebSocket,只需正确设置标头以处理Upgrade请求,将连接从HTTP升级为WebSocket。
延伸阅读
- WebSocket 代理,详见 nginx.org
- NGINX与NGINX Plus功能对比
- NGINX Plus技术规格
- 配置WebSocket流量代理,位于:
关于作者

相关博客文章
NGINX Plus R26 正式发布
NGINX Plus R26通过缓存JSON Web密钥集加快JWT验证,并强化TLS握手,从而提升安全性。NGINX JavaScript的新功能包括增强对异步函数的支持,以及实现WebCrypto API。
使用NGINX App Protect DoS保护gRPC应用,抵御严重的DoS攻击
gRPC具备开发人员设计和部署现代应用所需的速度与灵活性,但其开放性也使其极易受到第7层DoS攻击。NGINX App Protect DoS可保护gRPC应用免受此类破坏性攻击。
Ingress Controller 选型指南(第 2 部分):风险与面向未来的规划
了解选择错误的Ingress控制器可能带来的风险,以及如何从关键方面着手,让您的选择更好地适应未来需求。
NGINX Plus R19 正式发布
NGINX Plus R19扩展了监控功能,不仅提供更多指标,还新增了指标分析方式;增加试运行模式,用于测试限速效果;增强键值存储,以支持IP地址范围;并使限速更加动态。
NGINX现已正式加入F5
NGINX现已正式成为F5的一部分。Gus Robertson现任F5 NGINX业务部门负责人。他阐述了两家公司在人才、文化和愿景方面融合的价值,以及双方将如何携手增强NGINX的开源产品和商业产品。
