利用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的实现过程,其中红色重点标注了发心跳包的内容):
<script>
$(document).ready(function () {
window.websocket = {};
var userId = 'zqh';
var api = 'localhost:8080';
var msg = 'hello websocket';
var app = {
/**
*初始化socket,判断是否支持webSocket
*/
initSocket: function () {
if ('WebSocket' in window) {
websocket = new WebSocket("ws://" + api + "/webscoket/ID=" + userId);
} else if ('MozWebSocket' in window) {
websocket = new MozWebSocket("ws://" + api + "/webscoket/ID=" + userId);
} else {
websocket = new SockJS("http://" + api + "/sockjs/webscoket/ID=" + userId);
}
app.state();
},
/**
* 状态
*/
state: function () {
// 打开连接时
websocket.onopen = function (evnt) {
heartCheck.reset().start();
console.log("websocket已启用");
document.getElementById("WebSocketStatus").innerText = "websocket已启用";
};
// 收到消息时
websocket.onmessage = function (event) {
heartCheck.reset().start();
document.getElementById("receivemsg").innerText = event.data;
};
//出错时
websocket.onerror = function (evnt) {
console.log("与后台握手出现问题!");
};
//关闭时
websocket.onclose = function (evnt) {
console.log("正在关闭 webSocket ");
};
}
};
app.initSocket();
});
// 心跳检测,每隔一段时间检测连接状态,如果处于连接中,就像Server主动发送消息,来重置Server段与客户端的最大连接时间,如果已经断开,发起重连
var heartCheck = {
// 9分钟发起一次心跳,比Server端设置的连接时间稍微小一点,在接近断开的情况下以通信的方式去重置连接时间
timeout: 550000,
serverTimeoutObj: null,
reset: function () {
clearTimeout(this.serverTimeoutObj);
return this;
},
start: function () {
this.serverTimeoutObj = setInterval(function () {
if (websocket.readyState == 1) {
console.log("连接状态,发送消息保持连接");
websocket.send("ping");
// 如果获取到消息,说明连接正常,重置心跳检测
heartCheck.reset().start();
} else {
console.log("断开连接,尝试重连");
app.initSocket();;
}
}, this.timeout)
}
};
function send() {
var msg = document.getElementById("sendmsg").value;
heartCheck.reset().start();
//发送消息
websocket.send(msg);
}
</script>
上述过程就是保持长连接的过程。
参考文章:https://blog.youkuaiyun.com/cm786526/article/details/79939687