nginx反向代理WebSocket

WebSocket協議相比較於HTTP協議成功握手後能夠屢次進行通信,直到鏈接被關閉。可是WebSocket中的握手和HTTP中的握手兼容, 它使用HTTP中的Upgrade協議頭將鏈接從HTTP升級到WebSocket。這使得WebSocket程序能夠更容易的使用現已存在的基礎設施。javascript

WebSocket工做在HTTP的80和443端口並使用前綴ws://或者wss://進行協議標註,在創建鏈接時使用HTTP/1.1的101狀態碼進行協議切換, 當前標準不支持兩個客戶端之間不借助HTTP直接創建Websocket鏈接。html

更多Websocket的介紹可參考我寫的 聊一聊WebSocket 一文。java

開發小程序的時候須要用到WebSocket長鏈接和推送技術,可是必須使用wss,而且必須經過域名訪問。這時候就須要用到nginx反向代理了。nginx

原理 通常咱們開發的WebSocket服務程序使用ws協議,明文的。可是怎樣讓它安全的經過互聯網傳輸呢?這時候能夠經過nginx在客戶端和服務端直接作一個轉發了, 客戶端經過wss訪問,而後nginx和服務端經過ws協議通訊。web

以下圖所示:小程序

配置 前提條件是你有一個域名,而且申請好了證書。瀏覽器

nginx版本: 1.12 nginx相關配置內容以下:安全

map $http_upgrade $connection_upgrade {
    default upgrade;
    '' close;
}

upstream websocket {
    server localhost:port; # 這裏port改爲你的websocket端口
}

server {
     server_name xxx.com;
     listen 443 ssl;
     location / {
         proxy_pass http://websocket;
         proxy_read_timeout 300s;
         proxy_send_timeout 300s;
         
         proxy_set_header Host $host;
         proxy_set_header X-Real-IP $remote_addr;
         proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
         
         proxy_http_version 1.1;
         proxy_set_header Upgrade $http_upgrade;
         proxy_set_header Connection $connection_upgrade;
     }
    ssl_certificate /etc/letsencrypt/live/test.enzhico.net/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/test.enzhico.net/privkey.pem;
}
複製代碼

之類解釋一下關鍵配置部分:bash

最重要的就是在反向代理的配置中增長了以下兩行,其它的部分和普通的HTTP反向代理沒有任何差異。服務器

proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
複製代碼

這裏面的關鍵部分在於HTTP的請求中多了以下頭部:

Upgrade: websocket
Connection: Upgrade
複製代碼

這兩個字段表示請求服務器升級協議爲WebSocket。服務器處理完請求後,響應以下報文:

# 狀態碼爲101
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: upgrade
複製代碼

告訴客戶端已成功切換協議,升級爲Websocket協議。握手成功以後,服務器端和客戶端便角色對等,就像普通的Socket同樣,可以雙向通訊。 再也不進行HTTP的交互,而是開始WebSocket的數據幀協議實現數據交換。

這裏使用map指令能夠將變量組合成爲新的變量,會根據客戶端傳來的鏈接中是否帶有Upgrade頭來決定是否給源站傳遞Connection頭, 這樣作的方法比直接所有傳遞upgrade更加優雅。

默認狀況下,鏈接將會在無數據傳輸60秒後關閉,proxy_read_timeout參數能夠延長這個時間。源站經過按期發送ping幀以保持鏈接並確認鏈接是否還在使用。

兩個超時參數

proxy_read_timeout

語法 proxy_read_timeout time 默認值 60s 上下文 http server location 說明 該指令設置與代理服務器的讀超時時間。它決定了nginx會等待多長時間來得到請求的響應。 這個時間不是得到整個response的時間,而是兩次reading操做的時間。

proxy_send_timeout

語法 proxy_send_timeout time 默認值 60s 上下文 http server location 說明 這個指定設置了發送請求給upstream服務器的超時時間。超時設置不是爲了整個發送期間,而是在兩次write操做期間。 若是超時後,upstream沒有收到新的數據,nginx會關閉鏈接

屢次代理轉發

工做中碰見過一種狀況,就是某個域名在移動網絡下面訪問不了,這樣的話我須要經過一個前段代理服務器作轉發,這樣就涉及到兩次代理。

好比訪問的websocket服務URL爲:

wss://xxx.com
複製代碼

只須要最外層使用wss協議,裏面的交互都使用ws協議,因此監聽80端口便可。

瀏覽器調試以下:

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <title></title>
    <script type="text/javascript">
        ws = new WebSocket("wss://xxx.com");
        ws.onopen = function() {
            alert("鏈接成功");
            ws.send('tom');
            alert("給服務端發送一個字符串:tom");
        };
        ws.onmessage = function(e) {
            alert("收到服務端的消息:" + e.data);
        };
    </script>
</head>

<body>
</body>

</html>

複製代碼

參考鏈接

相關文章
相關標籤/搜索