Nginx反向代理WebSocket(WSS)


1. WebSocket協議

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支持WebSocket。對於NGINX將升級請求從客戶端發送到后台服務器,必須明確設置Upgrade和Connection標題。

 

2. Nginx配置

 Nginx通過在客戶端和后端服務器之間建立隧道來支持WebSockets通信。為了讓Nginx可以將來自客戶端的Upgrade請求發送到后端服務器,Upgrade和Connection的頭信息必須被顯式的設置。

1)編輯nginx.conf,在http區域內一定要添加下面配置:
map $http_upgrade $connection_upgrade {
    default upgrade;
    '' close;
}
 
map指令的作用:
該作用主要是根據客戶端請求中$http_upgrade 的值,來構造改變$connection_upgrade的值,即根據變量$http_upgrade的值創建新的變量$connection_upgrade,
創建的規則就是{}里面的東西。其中的規則沒有做匹配,因此使用默認的,即 $connection_upgrade 的值會一直是 upgrade。然后如果 $http_upgrade為空字符串的話,
那值會是 close。
 
 
2)編輯vhosts下虛擬主機的配置文件,在location匹配配置中添加如下內容:
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
 
示例如下:
upstream socket.kevin.com {
    hash $remote_addr consistent;
    server 10.0.12.108:9000;
    server 10.0.12.109:9000;
}
 
 location / {
            proxy_pass http://socket.kevin.com/;
            proxy_set_header Host $host:$server_port;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
        }

3)可能會出現跨域問題,server區塊填寫以下跨域配置即可

add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
if ($request_method = 'OPTIONS') {
return 204;
}

 一旦我們完成以上設置,Nginx就可以處理WebSocket連接了

 

proxy_http_version 1.1;,為什么使用http1.1協議?(https://blog.csdn.net/moxiaomomo/article/details/74734565)

設置代理使用的HTTP協議版本。默認使用的版本是1.0,而1.1版本則推薦在使用keepalive連接時一起使用。

因為http1.0不支持keepalive特性,當沒有使用http1.1的時候,后端服務會返回101錯誤,然后斷開連接。

 

map的作用

1.map的作用主要是根據客戶端請求中 $http_upgrade 的值,來構造改變 $connection_upgrade 的值,即根據變量 $http_upgrade 的值創建新的變量 $connection_upgrade,創建的規則就是 {} 里面的東西,上圖代碼中(第一個標記點)的規則沒有做匹配,因此使用默認的,即 $connection_upgrade 的值會一直是 upgrade。然后如果 $http_upgrade為空字符串的話,那值會是 close。

 

HTTP的Upgrade協議頭

HTTP的Upgrade協議頭機制用於將連接從HTTP連接升級到WebSocket連接,Upgrade機制使用了Upgrade協議頭和Connection協議頭;為了讓Nginx可以將來自客戶端的Upgrade請求發送到后端服務器,Upgrade和Connection的頭信息必須被顯式的設置。

 

3. Nginx代理WebSocket保持長連接的方案

現象描述:用nginx反代代理某個業務,發現平均1分鍾左右,就會出現webSocket連接中斷,然后查看了一下,是nginx出現的問題。
產生原因:nginx等待第一次通訊和第二次通訊的時間差,超過了它設定的最大等待時間,簡單來說就是超時!

解決方法1
其實只要配置nginx.conf的對應localhost里面的這幾個參數就好
proxy_connect_timeout;
proxy_read_timeout;
proxy_send_timeout;

解決方法2
發心跳包,原理就是在有效地再讀時間內進行通訊,重新刷新再讀時間

 

http {
    server {
        location / {
            root   html;
            index  index.html index.htm;
            proxy_pass http://webscoket;
            proxy_http_version 1.1;
            proxy_connect_timeout 4s;                #配置點1
            proxy_read_timeout 60s;                  #配置點2,如果沒效,可以考慮這個時間配置長一點
            proxy_send_timeout 12s;                  #配置點3
            proxy_set_header Upgrade $http_upgrade; 
            proxy_set_header Connection "Upgrade";  
        }
    }
}

關於上面配置2的解釋
這個是服務器對你等待最大的時間,也就是說當你webSocket使用nginx轉發的時候,用上面的配置2來說,如果60秒內沒有通訊,依然是會斷開的,所以,你可以按照你的需求來設定。比如說,我設置了10分鍾,那么如果我10分鍾內有通訊,或者10分鍾內有做心跳的話,是可以保持連接不中斷的,詳細看個人需求

WebSocket與Socket的關系
- Socket其實並不是一個協議,而是為了方便使用TCP或UDP而抽象出來的一層,是位於應用層和傳輸控制層之間的一組接口。當兩台主機通信時,必須通過Socket連接,Socket則利用TCP/IP協議建立TCP連接。TCP連接則更依靠於底層的IP協議,IP協議的連接則依賴於鏈路層等更低層次。
- WebSocket就像HTTP一樣,則是一個典型的應用層協議。
總的來說:Socket是傳輸控制層接口,WebSocket是應用層協議。

 

參考:

https://www.cnblogs.com/kevingrace/p/9512287.html

https://yq.aliyun.com/articles/73865

https://www.cnblogs.com/piperck/p/7066286.html

http://www.ttlsa.com/nginx/using-nginx-map-method/

https://blog.csdn.net/chszs/article/details/26369257

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM