開(kāi)放、平等、協(xié)作、快速、分享
利用nginx代理websocket的時(shí)候,發(fā)現(xiàn)客戶(hù)端和服務(wù)器握手成功后,如果在60s時(shí)間內(nèi)沒(méi)有數(shù)據(jù)交互,連接就會(huì)自動(dòng)斷開(kāi),如下圖:
為了保持長(zhǎng)連接,可以采取來(lái)兩種方式.
1.nginx.conf 文件里location 中的proxy_read_timeout 默認(rèn)60s斷開(kāi),可以把他設(shè)置大一點(diǎn),你可以設(shè)置成自己需要的時(shí)間,我這里設(shè)置的是十分鐘(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;
}
}
按照上述方法設(shè)置好后,我們可以發(fā)現(xiàn),如果在10分鐘之內(nèi)沒(méi)有數(shù)據(jù)交互的話(huà),websocket連接就會(huì)自動(dòng)斷開(kāi),所以這種方式還是有點(diǎn)問(wèn)題,如果我頁(yè)面停留時(shí)間超過(guò)十分鐘而且又沒(méi)有數(shù)據(jù)交互的話(huà),連接還是會(huì)斷開(kāi)的,所以需要同時(shí)結(jié)合第二種方法.
上面nginx配置的時(shí)候還出了一個(gè)小插曲,微改了nginx配置之后,沒(méi)有重啟nginx服務(wù),導(dǎo)致設(shè)置的過(guò)期時(shí)間一直沒(méi)有生效,所以需要用 sudo nginx -s reload 重啟nginx服務(wù)
2.在nginx延長(zhǎng)超時(shí)時(shí)間的基礎(chǔ)上,前端在超時(shí)時(shí)間內(nèi)發(fā)心跳包,刷新再讀時(shí)間,前端具體實(shí)現(xiàn)見(jiàn)如下代碼(此處代碼包含了前端整個(gè)websocket的實(shí)現(xiàn)過(guò)程,其中紅色重點(diǎn)標(biāo)注了發(fā)心跳包的內(nèi)容):
// websocket連接
var websocket_connected_count = 0;
var onclose_connected_count = 0;
function newWebSocket(){
var websocket = null;
// 判斷當(dāng)前環(huán)境是否支持websocket
if(window.WebSocket){
if(!websocket){
var ws_url ="wss://"+domain+"/updatewebsocket";
websocket = new WebSocket(ws_url);
}
}else{
Tip("not support websocket");
}
// 連接成功建立的回調(diào)方法
websocket.onopen = function(e){
heartCheck.reset().start(); // 成功建立連接后,重置心跳檢測(cè)
Tip("connected successfully")
}
// 連接發(fā)生錯(cuò)誤,連接錯(cuò)誤時(shí)會(huì)繼續(xù)嘗試發(fā)起連接(嘗試5次)
websocket.onerror = function() {
console.log("onerror連接發(fā)生錯(cuò)誤")
websocket_connected_count++;
if(websocket_connected_count <= 5){
newWebSocket()
}
}
// 接受到消息的回調(diào)方法
websocket.onmessage = function(e){
console.log("接受到消息了")
heartCheck.reset().start(); // 如果獲取到消息,說(shuō)明連接是正常的,重置心跳檢測(cè)
var message = e.data;
if(message){
//執(zhí)行接收到消息的操作,一般是刷新UI
}
}
// 接受到服務(wù)端關(guān)閉連接時(shí)的回調(diào)方法
websocket.onclose = function(){
Tip("onclose斷開(kāi)連接");
}
// 監(jiān)聽(tīng)窗口事件,當(dāng)窗口關(guān)閉時(shí),主動(dòng)斷開(kāi)websocket連接,防止連接沒(méi)斷開(kāi)就關(guān)閉窗口,server端報(bào)錯(cuò)
window.onbeforeunload = function(){
websocket.close();
}
// 心跳檢測(cè), 每隔一段時(shí)間檢測(cè)連接狀態(tài),如果處于連接中,就向server端主動(dòng)發(fā)送消息,來(lái)重置server端與客戶(hù)端的最大連接時(shí)間,如果已經(jīng)斷開(kāi)了,發(fā)起重連。
var heartCheck = {
timeout: 55000, // 9分鐘發(fā)一次心跳,比server端設(shè)置的連接時(shí)間稍微小一點(diǎn),在接近斷開(kāi)的情況下以通信的方式去重置連接時(shí)間。
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("連接狀態(tài),發(fā)送消息保持連接");
websocket.send("ping");
heartCheck.reset().start(); // 如果獲取到消息,說(shuō)明連接是正常的,重置心跳檢測(cè)
}else{
console.log("斷開(kāi)狀態(tài),嘗試重連");
newWebSocket();
}
}, this.timeout)
}
}
}
上述過(guò)程就是保持長(zhǎng)連接的過(guò)程,前端部分也包含了大部分websocket初始化的內(nèi)容
————————————————
版權(quán)聲明:本文為CSDN博主「晴識(shí)明月」的原創(chuàng)文章,遵循 CC 4.0 BY-SA 版權(quán)協(xié)議,轉(zhuǎn)載請(qǐng)附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/cm786526/article/details/79939687
24小時(shí)免費(fèi)咨詢(xún)
請(qǐng)輸入您的聯(lián)系電話(huà),座機(jī)請(qǐng)加區(qū)號(hào)