今天遇到这样一些错误,中文的意思是 websocket 已经关闭了
简单查了一些资料分析如下
WebSocket断开的原因有很多,服务端客户端主动断开(服务器宕机服务停止,客户端关闭网页),网络不稳定被动断开(物理层断开,或者网络底层数据错误)
我们可以将错误日志打印出来
ws.onclose = function (e) {
logger.error('websocket 断开');
logger.info(e.code + ' ' + e.reason + ' ' + e.wasClean);
}
WS 断开时,会触发CloseEvent
, CloseEvent会在连接关闭时发送给使用 WS 的客户端. 它在 WS 对象的 onclose 事件监听器中使用。
CloseEvent有三个字段需要注意, 通过分析这三个字段,一般就可以找到断开原因
CloseEvent.code
: code是错误码,numberCloseEvent.reason
: reason是断开原因,stringCloseEvent.wasClean
: wasClean表示是否正常断开,boolean,异常断开时,该值为false监测到断开后,客户端重新发出连接
如果还是没有链接成功,界面提示用户,由于网络问题,需要重新打开浏览器,或者请检查网络
例如:这是服务端 server 代码
const WebSocket = require('ws');
const ws = new WebSocket.Server({ server });
ws.on('connection', function connection(socket) {
// 当接受消息,打印日志
socket.on('message', function incoming(data) {
console.log('Incoming data ', data);
});
});
这是客户端 client 代码
// 创建 WS 链接
const socket = new WebSocket('ws://localhost:8080');
// 监听连接事件
socket.addEventListener('open', function(event) {
console.log("Connected to server");
});
// 监听消息事件
socket.addEventListener('message', function(event) {
console.log('Message from server ', event);
});
// 发送数据
var data = {name: 'admin'};
socket.send(JSON.stringify(data));
可以在发送数据前,检查一下是否链接
function isOpen(ws) {
return ws.readyState === ws.OPEN
}
if (isOpen(socket)) {
var data = {name: 'admin'};
socket.send(JSON.stringify(data));
} else {
logger.info('web socket is closing, reconnecting');
}
这是参考另一个思路,设置心跳监测连接,断线重连(借鉴 https://www.cnblogs.com/gxp69/p/11736749.html 的思路)
var lockReconnect = false; // 避免ws重复连接
var ws = null; // 判断当前浏览器是否支持WebSocket
var wsUrl = socketUrl;
// 连接ws
createWebSocket(wsUrl);
/**
* 创建 WS 实例
* @param {string} url ws的URL
*/
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 () {
reconnect(wsUrl);
console.log("WS 连接关闭!" + new Date().toLocaleString());
};
ws.onerror = function () {
reconnect(wsUrl);
console.log("WS 连接错误!");
};
ws.onopen = function () {
//心跳检测重置
heartCheck.reset().start();
console.log("WS 连接成功!" + new Date().toLocaleString());
};
ws.onmessage = function (event) {
//如果获取到消息,心跳检测重置
//拿到任何消息都说明当前连接是正常的
heartCheck.reset().start();
console.log("WS 收到消息啦:" +event.data);
if (event.data != 'pong') {
let data = JSON.parse(event.data);
}
};
}
// 监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
window.onbeforeunload = function() {
ws.close();
}
/**
* 重连
* @param {string} url ws的URL
* @returns null
*/
function reconnect(url) {
if (lockReconnect) return;
lockReconnect = true;
// 没连接上,会一直重连,设置延迟 2s 避免连接频繁
setTimeout(function () {
createWebSocket(url);
lockReconnect = false;
}, 2000);
}
// 心跳检测
var heartCheck = {
timeout: 1000,
timeoutObj: null,
serverTimeoutObj: null,
reset: function() {
clearTimeout(this.timeoutObj);
clearTimeout(this.serverTimeoutObj);
return this;
},
start: function() {
var self = this;
this.timeoutObj = setTimeout(function() {
//这里发送一个心跳,后端收到后,返回一个心跳消息,
//onmessage拿到返回的心跳就说明连接正常
ws.send("ping");
console.log("ping!")
//如果超过一定时间还没重置,说明后端主动断开了
self.serverTimeoutObj = setTimeout(function() {
//如果onclose会执行reconnect,我们执行ws.close()就行了.如果直接执行reconnect 会触发onclose导致重连两次
ws.close();
}, self.timeout)
}, this.timeout)
}
}