WebSocket is already in CLOSING or CLOSED state

WebSocket is already in CLOSING or CLOSED state. 报错信息的解决方案

今天遇到这样一些错误,中文的意思是 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是错误码,number
  • CloseEvent.reason: reason是断开原因,string
  • CloseEvent.wasClean: wasClean表示是否正常断开,boolean,异常断开时,该值为false

解决方案1

监测到断开后,客户端重新发出连接

如果还是没有链接成功,界面提示用户,由于网络问题,需要重新打开浏览器,或者请检查网络
在这里插入图片描述

例如:这是服务端 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');
}

解决方案2

这是参考另一个思路,设置心跳监测连接,断线重连(借鉴 https://www.cnblogs.com/gxp69/p/11736749.html 的思路)

扫描二维码关注公众号,回复: 14979533 查看本文章
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)
  }
}

参考链接

Stack Overflow

心跳监测介绍

CSDN

CSDN

猜你喜欢

转载自blog.csdn.net/weixin_41697143/article/details/126543145