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