1. 程式人生 > >Nginx代理webSocket時60s自動斷開, 怎麼保持長連線

Nginx代理webSocket時60s自動斷開, 怎麼保持長連線

利用nginx代理websocket的時候,發現客戶端和伺服器握手成功後,如果在60s時間內沒有資料互動,連線就會自動斷開,如下圖:


為了保持長連線,可以採取來兩種方式.

1.nginx.conf 檔案裡location 中的proxy_read_timeout 預設60s斷開,可以把他設定大一點,你可以設定成自己需要的時間,我這裡設定的是十分鐘(600s).

nginx配置如下:

server {
		listen 80;
		server_name carrefourzone.senguo.cc;
		#error_page 502 /static/502.html;

		location /static/ {
		    root /home/chenming/Carrefour/carrefour.senguo.cc/source;
		    expires 7d;
        	}

		location / {
		    proxy_pass_header Server;
		    proxy_set_header Host $http_host;
		    proxy_redirect off;
		    proxy_set_header X-Real-IP $remote_addr;
		    proxy_set_header X-Scheme $scheme;
		    proxy_pass       http://127.0.0.1:9887;
		    proxy_http_version  1.1;
		    proxy_set_header    Upgrade    "websocket";
		    proxy_set_header    Connection "Upgrade";
		    proxy_read_timeout 600s; 
		}
	}

按照上述方法設定好後,我們可以發現,如果在10分鐘之內沒有資料互動的話,websocket連線就會自動斷開,所以這種方式還是有點問題,如果我頁面停留時間超過十分鐘而且又沒有資料互動的話,連線還是會斷開的,所以需要同時結合第二種方法.

上面nginx配置的時候還出了一個小插曲,微改了nginx配置之後,沒有重啟nginx服務,導致設定的過期時間一直沒有生效,所以需要用 sudo nginx -s reload  重啟nginx服務

2.在nginx延長超時時間的基礎上,前端在超時時間內發心跳包,重新整理再讀時間,前端具體實現見如下程式碼(此處程式碼包含了前端整個websocket的實現過程,其中紅色重點標註了發心跳包的內容):

// websocket連線
var websocket_connected_count = 0;
var onclose_connected_count = 0;
function newWebSocket(){
    var websocket = null;
    // 判斷當前環境是否支援websocket
    if(window.WebSocket){
        if(!websocket){
            var ws_url ="wss://"+domain+"/updatewebsocket";
            websocket = new WebSocket(ws_url);
        }
    }else{
        Tip("not support websocket");
    }

    // 連線成功建立的回撥方法
    websocket.onopen = function(e){
        heartCheck.reset().start();   // 成功建立連線後,重置心跳檢測
Tip("connected successfully") } // 連線發生錯誤,連線錯誤時會繼續嘗試發起連線(嘗試5次) websocket.onerror = function() { console.log("onerror連線發生錯誤") websocket_connected_count++; if(websocket_connected_count <= 5){ newWebSocket() } } // 接受到訊息的回撥方法 websocket.onmessage = function(e){ console.log("接受到訊息了") heartCheck.reset().start(); // 如果獲取到訊息,說明連線是正常的,重置心跳檢測 var message = e.data; if(message){ //執行接收到訊息的操作,一般是重新整理UI } } // 接受到服務端關閉連線時的回撥方法 websocket.onclose = function(){ Tip("onclose斷開連線"); } // 監聽視窗事件,當視窗關閉時,主動斷開websocket連線,防止連線沒斷開就關閉視窗,server端報錯 window.onbeforeunload = function(){ websocket.close(); } // 心跳檢測, 每隔一段時間檢測連線狀態,如果處於連線中,就向server端主動傳送訊息,來重置server端與客戶端的最大連線時間,如果已經斷開了,發起重連。 var heartCheck = { timeout: 55000, // 9分鐘發一次心跳,比server端設定的連線時間稍微小一點,在接近斷開的情況下以通訊的方式去重置連線時間。 serverTimeoutObj: null, reset: function(){ clearTimeout(this.timeoutObj); clearTimeout(this.serverTimeoutObj); return this; }, start: function(){ var self = this; this.serverTimeoutObj = setInterval(function(){ if(websocket.readyState == 1){ console.log("連線狀態,傳送訊息保持連線"); websocket.send("ping"); heartCheck.reset().start(); // 如果獲取到訊息,說明連線是正常的,重置心跳檢測 }else{ console.log("斷開狀態,嘗試重連"); newWebSocket(); } }, this.timeout) } } }

上述過程就是保持長連線的過程,前端部分也包含了大部分websocket初始化的內容.