欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  网络运营

使用Nginx做WebSockets代理教程

程序员文章站 2022-06-13 19:26:42
websocket 协议提供了一种创建支持客户端和服务端实时双向通信web应用程序的方法。作为html5规范的一部分,websockets简化了开发web实时通信程序的难度...

websocket 协议提供了一种创建支持客户端和服务端实时双向通信web应用程序的方法。作为html5规范的一部分,websockets简化了开发web实时通信程序的难度。目前主流的浏览器都支持websockets,包括火狐、ie、chrome、safari以及opera等,而且,越来越多的服务器应用框架也开始支持websockets。

要在企业产品中使用websockets,为满足高性能和高可用性,需要多个websocket服务器。负载均衡层需要支持websocket协议。nginx从1.3版起就开始支持websocket协议,而且可以担当websocket应用程序的反向代理以及实现负载均衡。

websocket协议和http协议不同,但是websocket协议的握手和http是兼容的,它使用http的upgrade协议头将连接从http连接升级到websocket连接。这个特性使得websocket应用程序可以很容易地应用到现有的基础设施。例如,websocket应用可以使用标准的80和443 http端口,因此可以通过现有的防火墙设施。

websockets应用程序会在客户端和服务器之间建立一个长连接,使得开发实时应用很容易。http的upgrade协议头机制用于将连接从http连接升级到websocket连接,upgrade机制使用了upgrade协议头和connection协议头。反向代理服务器在支持websocket协议方面面临着一些挑战。挑战之一是websocket是一个逐段转发(hop-by-hop)协议,因此当代理服务器拦截到来自客户端的upgrade请求时,代理服务器需要将自己的upgrade请求发送给后端服务器,包括适合的请求头。而且,由于websocket连接是长连接,与传统的http端连接截然不同,故反向代理服务器还需要允许这些连接处于打开(open)状态,而不能因为其空闲就关闭了连接。

nginx通过在客户端和后端服务器之间建立隧道来支持websockets通信。为了让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";
}

一旦我们完成以上设置,nginx就可以处理websocket连接了。

nginx websockets 实例

下面的例子讲述了nginx是如何为websocket做代理的。此例将使用ws模块,它是基于node.js构建的websocket实现。nginx将担当反向代理服务器,后端服务器是一个使用了ws和node.js的简单websockets应用。例子使用的命令在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上创建一个符号连接来允许我们使用“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

该程序会输出一条初始化消息“server started”,之后监听8010端口,等待客户端的连接。它会处理收到的所有请求,并且将接收到的消息输出在控制台,之后向客户端返回一条包含该消息的消息。我们希望nginx去代理客户端的请求,可以通过下面的配置实现:
复制代码 代码如下:

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 "upgrade";
    }
}

上面的配置会使nginx监听8020端口,并把任何接收到的请求转发给后端的websocket服务器,让后端服务器更好地处理websocket协议。我们可以使用wscat作为客户端来测试一下:

复制代码 代码如下:

/root/node_modules/ws/bin/wscat –connect ws://192.168.100.20:8020

上面的命令会通过nginx反向代理服务器和后端websocket服务器建立连接,你可以向服务器发送任意消息,然后服务器会返回一条消息。每当你在客户端发送一条消息,在后端服务器上能看到该消息的输出,之后在客户端会显示一条来自服务端的消息。
这是一个交互示例:

server:

client:

$ node server.js

 

server started

 

 

wscat –connect ws://192.168.100.20:8020

 

connected (press ctrl+c to quit)

 

> hello

received from client: hello

 

 

< server received from client: hello

由此我们可以看到客户端与服务器能通过nginx反向代理建立websockets通信,而且消息可以持续地进行双向传输,直至客户端或服务器断开连接。为了让nginx能正确处理websocket连接,只需正确地设置消息头来处理从http连接升级到websocket连接的upgrade请求。