「應用中間件」使用NGINX作為WebSocket代理
- 2019 年 10 月 7 日
- 筆記
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升級工具將連接從HTTP升級到WebSocket。這使得WebSocket應用程式更容易地適應現有的基礎設施。例如,WebSocket應用程式可以使用標準的HTTP埠80和443,從而允許使用現有的防火牆規則。
WebSocket應用程式在客戶機和伺服器之間保持長時間運行的連接,從而促進實時應用程式的開發。用於將連接從HTTP升級到WebSocket的HTTP升級機制使用升級和連接頭。反向代理伺服器在支援WebSocket方面面臨一些挑戰。一個是WebSocket是一個逐跳協議,因此當代理伺服器攔截來自客戶機的升級請求時,它需要將自己的升級請求發送到後端伺服器,包括適當的頭文件。此外,由於WebSocket連接是長壽命的,與HTTP使用的典型短壽命連接相反,反向代理需要允許這些連接保持打開狀態,而不是因為它們看起來是空閑的而關閉它們。
NGINX支援WebSocket,允許在客戶機和後端伺服器之間建立隧道。NGINX要將升級請求從客戶端發送到後端伺服器,必須顯式設置升級和連接頭,如下例所示:
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 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
Node.js在Ubuntu上安裝為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
伺服器列印一個初始的「server started」消息,然後監聽埠8010,等待客戶機連接到它。當它接收到客戶端請求時,它會對其進行回顯,並向客戶端發送包含它接收到的消息的消息。要有NGINX代理這些請求,我們創建以下配置:
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; } } }
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要發送到伺服器的消息時,您將看到它在伺服器上發出回顯,然後來自伺服器的一條消息出現在客戶機上。下面是一個互動的例子:
Server:Client:$ node server.js
Server started
wscat –connect ws://192.168.100.20:8020
Connected (press CTRL+C to quit)
> HelloReceived from client: Hello < Server received from client: Hello
這裡我們看到客戶機和伺服器能夠通過NGINX進行通訊,NGINX充當代理,消息可以繼續來回發送,直到客戶機或伺服器斷開連接。要使NGINX正確處理WebSocket,所需要做的就是正確地設置頭文件,以處理將連接從HTTP升級到WebSocket的升級請求。
原文:https://www.nginx.com/blog/websocket-nginx/
本文:https://pub.intelligentx.net/nginx-websocket-proxy
討論:請加入知識星球或者小紅圈【首席架構師圈】