如何解决webSocket自动断开连接
dearweb
发布:2022-07-01 23:51:20阅读:
一般情况下,前端页面连接WebSocket服务的时候都是通过Nginx等负载均衡,然后由Nginx去代理连接后端的socket服务。Nginx的配置类似如下:
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
location / {
proxy_pass https://socket;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}如果建立连接之后不做一些措施,那么可能会有各种各样的原因会导致socket断开,最好在socket断开时将错误打印出来。
ws.onclose = function (ev) {
console.log('socket 断开: ' + ev.code + ' ' + ev.reason + ' ' + ev.wasClean)
}socket断开时,会触发CloseEvent, CloseEvent会在连接关闭时发送给使用 WebSocket 的客户端,它在 WebSocket 对象的 onclose 事件监听器中使用。 CloseEvent有三个字段需要注意, 通过分析这三个字段,一般就可以找到断开原因:
CloseEvent.code: code是错误码,是整数类型
CloseEvent.reason: reason是断开原因,是字符串
CloseEvent.wasClean: wasClean表示是否正常断开,是布尔值。一般异常断开时,该值为false

为了保证socket稳定,不断开,最好也是最简单的办法是添加一些逻辑,一直保持socket处在连接的状态。常见的做法就是间隔发ping消息给服务端,服务端接收到这个消息之后返回pong消息,以此来保持心跳,以防sock断开。我们常见的ping消息和pong消息实际上是发送了一个文本消息,这个消息的内容是ping或者pong,甚至是heatbeat等等,但是从socket协议来说是有设计ping消息和pong消息的。在socket的数据帧中,有一个opcode,它表明了socket的数据帧是什么类型的:
%x0:表示一个延续帧。当Opcode为0时,表示本次数据传输采用了数据分片,当前收到的数据帧为其中一个数据分片。
%x1:表示这是一个文本帧(frame)
%x2:表示这是一个二进制帧(frame)
%x3-7:保留的操作代码,用于后续定义的非控制帧。
%x8:表示连接断开。
%x9:表示这是一个ping操作。
%xA:表示这是一个pong操作。
%xB-F:保留的操作代码,用于后续定义的控制帧。
规范的心跳应该是在opcode里定义type:ping(9)才对,消息的内容是null,什么都没有,这才是最轻量级最规范的websocket心跳机制。一般情况下,使用发文本消息的方式也是没啥问题的,无非就是多消耗了一点流量和带宽,调试起来也容易一些,有可能心跳消息本身就会带一些业务数据。
js代码如下:
var lockReconnect = false;
var ws = null;
var wsUrl = 'wss://127.0.0.1/socket'
createWebSocket(wsUrl);
function createWebSocket(url) {
try{
if('WebSocket' in window){
ws = new WebSocket(url);
}
initEventHandle();
}catch(e){
reconnect(url);
console.log(e);
}
}
function initEventHandle() {
ws.onclose = function (ev) {
reconnect(wsUrl);
console.log('socket 断开: ' + ev.code + ' ' + ev.reason + ' ' + ev.wasClean)
};
ws.onerror = function (ev) {
reconnect(wsUrl);
console.log("llws连接错误!");
};
ws.onopen = function () {
heartCheck.reset().start();
console.log("llws连接成功!"+new Date().toLocaleString());
};
ws.onmessage = function (message) {
heartCheck.reset().start(); //拿到任何消息都说明当前连接是正常的
console.log("llws收到消息啦:" +message.data);
if(message.data!='pong'){
var msg = JSON.parse(message.data);
}
};
}当窗口关闭时,主动去关闭websocket连接
window.onbeforeunload = function() {
ws.close();
}
function reconnect(url) {
if(lockReconnect) return;
lockReconnect = true;
setTimeout(function () { //没连接上会一直重连,设置延迟避免请求过多
createWebSocket(url);
lockReconnect = false;
}, 2000);
}
var heartCheck = {
timeout: 3000,
timeoutObj: null,
serverTimeoutObj: null,
reset: function(){
clearTimeout(this.timeoutObj);
clearTimeout(this.serverTimeoutObj);
return this;
},
start: function(){
var self = this;
this.timeoutObj = setTimeout(function(){
ws.send("ping");
console.log("ping!")
self.serverTimeoutObj = setTimeout(function(){
//如果超过一定时间还没重置,说明后端主动断开了
ws.close();
}, self.timeout)
}, this.timeout)
}
}服务端Java代码:
@OnMessage
public void onMessage(String message, Session session) {
if(message.equals("ping")){
}else{
}
}小礼物走一波,支持作者
赏还没有人赞赏,支持一波吧