websocket 封装(含心跳,重连机制,强制退出)

Javascript · 2022-08-14

websocket 封装(含心跳,重连机制,强制退出)

/**
 * @param {JSON} json  连接建立立即发送,如果想不发送就传' ',
 * @param {String} url  
 * @param {Function} callback 接收服务端数据时触发的回调
 * @param {Object} protocol  第二个参数 protocol 是可选的,指定了可接受的子协议。
 */

const WS = function (json, url, callback, protocol) {
  this.json = json;
  this.url = url;
  this.protocol = typeof (protocol) == 'undefined' ? null : protocol || ''
  this.reconnect_time = 0; //重连的时间
  this.reconnect_count = 0; //重连次数
  this.is_destroy = false //强制关闭
  this.is_reconnect = false;  // 是否重连过
  this.last_health_time = -1; //上一次心跳时间
  this.keep_alive_timer; //心跳定时发送
  this.reconnect_timer; // 重连操作
  this.socket; //socket对象
  this.initWs();

  this.onopen = e => {
    if (this.socket) {
      this.socket.send(json);
      this.reconnect_count = 0; //重连上把重连次数清空
      this.reconnect_time = 0; //重连的时间清空
      if (this.socket.readyState === 1) {
        //保持心跳函数 30s发送一次
        this.keep_alive_timer = setInterval(() => {
          this.keepAlive();
        }, 30000);
      }
    }
  };

  this.onmessage = e => {
    try {
      callback(JSON.parse(e.data));
    } catch (error) {
      callback(e.data, error);
    }
  };

  this.onerror = e => {
    this.reConnect();
  };

  this.onclose = e => {
    let flag = sessionStorage.getItem('is_reconnect') || false
    if (flag || this.is_destroy || (new Date().getTime() - this.reconnect_time >= 20000 && this.reconnect_count >= 10)) { //强制关闭连接
      clearInterval(this.keep_alive_timer);
      this.socket = null
    } else {
      this.reConnect();
    }
  };
};

/**
 * 初始化websocket连接
 * @param url
 */
WS.prototype.initWs = function () {
  window.WebSocket = window.WebSocket || window.MozWebSocket;
  if (!window.WebSocket) { // 检测浏览器支持
    console.error('错误: 浏览器不支持websocket');
    return;
  }
  this.last_health_time = -1;  // 最近发送心跳的时间
  this.is_reconnect = false;
  this.is_destroy = false //强制关闭

  if (this.protocol) {
    this.socket = new WebSocket(this.url, this.protocol);
  } else {
    this.socket = new WebSocket(this.url);
  }
  this.socket.onopen = e => {
    this.onopen(e);
  };

  this.socket.onmessage = e => {
    this.onmessage(e);
  };

  this.socket.onclose = e => {
    this.onclose(e);
  };

  this.socket.onerror = e => {
    this.onerror(e);
  };
  return this;
};

/**
 * 保持心跳函数
 */
WS.prototype.keepAlive = function () {
  const socket = this.socket;
  const time = new Date().getTime();
  // 不是刚开始连接并且连接了50s(如果断网了,ws.send会无法发送消息出去)
  if (this.last_health_time !== -1 && time - this.last_health_time > 50000) {
    this.socket.close();
  } else {
    /*
    【readyState:
    CONNECTING:值为0,表示正在连接。
    OPEN:值为1,表示连接成功,可以通信了。
    CLOSING:值为2,表示连接正在关闭。
    CLOSED:值为3,表示连接已经关闭,或者打开连接失败。】
    ws.bufferedAmount === 0 发送完毕
     */
    if (socket.bufferedAmount === 0 && socket.readyState === 1) {
      if (this.json != '') {
        let heartBeat = ''
        if (typeof (this.json) == 'string') {
          heartBeat = this.json
        } else if (typeof (this.json) == 'object') {
          try {
            heartBeat = JSON.stringify(this.json)
          } catch (e) {
            e
          }
        }
        socket.send(heartBeat)
      }
      this.last_health_time = time;
    }
  }
};

/**
 * 断网重连
 */

WS.prototype.reConnect = function () {
  clearInterval(this.keep_alive_timer);
  if (!this.is_reconnect) {
    this.is_reconnect = true;
    this.reconnect_time = new Date().getTime();
    this.reconnect_count++;
    // 如果没有重连
    this.reconnect_timer && clearTimeout(this.reconnect_timer);
    this.reconnect_timer = setTimeout(() => { this.initWs() }, 2000);
  }
};

/**
 * 强制关闭
 */

WS.prototype.destroy = function () {
  clearInterval(this.keep_alive_timer);
  this.is_destroy = true;
  if(this.socket){
    this.socket.close()
  }
};

export default WS;

调用

/**(e) => {} 回调函数,
JSON.stringify(obj): 初始化成功就发送,可发送心跳
socketUrl: url地址
str: 子协议
**/
let ws = new WS(JSON.stringify(obj), socketUrl, (e) => {
ws.socket.send() 发送消息
},str)

// 关闭连接
ws.destroy()
javascript
  1. 123 2023-12-22

    123123123

Theme Jasmine by Kent Liao