websocket

115 阅读3分钟
/**
 * 发起websocket请求函数
 * @param {object} wsObj  - ws对象
*  @param {string} type  - 操作websocket:销毁close、创建create
*  @param {number} timeout  - 心跳间隔时长,默认5000ms
 * @param sendHeartBeat  - 以心跳,内容体区分string、object
 * @param {function} msgCallback  - 接收到ws数据,对数据进行处理的回调函数
 * @param {function} reCallback  - ws每次重连时,暴露对外的回调函数
 */
export function websocketCommand(wsObj,type,timeout=5000, sendHeartBeat, msgCallback, reCallback) {  
  let wsDestroy = type ==='close';  //  销毁标志
  let lockReconnect = false;  // 是否真正建立连接
  let timeoutObj = null;  // 心跳倒计时
  let serverTimeoutObj = null;  // 服务器心跳倒计时
  let timeoutnum = null;  // 断开 重连倒计时

  // 若type传入close,则意图销毁websocket
  if(type==='close'){
    clearTimeout(timeoutObj);
    clearTimeout(serverTimeoutObj);
    onClose();
  }
  // 若type传入create,则意图新建websocket,需初始化ws并发送心跳
  if(type==='create'){
    initWebsocket();
    websocketSend();  
  }

  function initWebsocket(){   
    if (typeof (WebSocket) === 'undefined') {
        console.log();('您的浏览器不支持WebSocket,无法获取数据');
        return false;
    }
    wsObj.onmessage = function (e) { onMessage(e) };
    wsObj.onopen = function () { onOpen() };
    wsObj.onerror = function () { onError() };
    wsObj.onclose = function () { onClose() } ;
  }

  function websocketSend () {
    // 加延迟是为了尽量让ws连接状态变为OPEN   
    setTimeout(() => { 
      // 添加状态判断,当为OPEN时,发送消息
      if (wsObj.readyState === wsObj.OPEN) { // wsObj.OPEN = 1 
        // console.log('类型',typeof sendHeartBeat);
        if( typeof sendHeartBeat == 'string'){
          // 若发送基本类型数据作为心跳,如字符串,直接将参数发送给服务端
          wsObj.send(sendHeartBeat)
        }else{
          // 若发送复杂类型数据作为心跳,如对象,则以回调方式暴露出去(得以支持动态数据)
          sendHeartBeat();
        }
      }
      // if (wsObj.readyState === wsObj.CLOSED) { // wsObj.CLOSED = 3 
      //   console.log('readyState=3')
      // }
    }, 500)
  }

  function onMessage(evt) {
    var received_msg = evt && JSON.parse(evt.data);
    msgCallback(received_msg);

    // 收到服务器信息, 重置服务器心跳
    start();
  }

  function onError() {
    console.log('ws_error');
    // 断网重连机制
    if(!wsDestroy){
      reconnect();
    }
  }

  function onOpen() {
    console.log("ws_open");
    // 连接成功向服务器发送信息,并开启心跳
    websocketSend();
    start();
  }

  function reconnect() {
    // 避免重复建立连接
    if (lockReconnect) { 
      return;
    }
    lockReconnect = true;
    // 没连接上会一直重连,设置延迟避免请求过多
    timeoutnum && clearTimeout(timeoutnum);
    timeoutnum = setTimeout(function() {
      // 重连
      initWebsocket();
      // 若重连后有需额外处理的逻辑,通过reCallback()回调暴露出去
      // reCallback?.();
      lockReconnect = false;
    }, timeout);
  }

  function start() {
   // 清计时器
    timeoutObj && clearTimeout(timeoutObj);
    serverTimeoutObj && clearTimeout(serverTimeoutObj);
    // 开启心跳
    timeoutObj = setTimeout(function() {
      if (wsObj.readyState == 1) {
        // 如果连接正常,发送心跳(服务端收到后会返回一条消息)
        websocketSend();
      } else {
        // 否则重连
        reconnect();
      }
      // 超时关闭
      serverTimeoutObj = setTimeout(function() {  
        wsObj.close();
      }, timeout);
    }, timeout);
  }

  function onClose() {
    if(!wsDestroy ){
      // 重连机制
      reconnect();
    }else if (wsObj.readyState == 1) {
      console.log('ws_close',wsObj);
     // 如果ws连接正常,则清计时器、断开连接
      clearTimeout(timeoutObj);
      clearTimeout(serverTimeoutObj);
      wsObj?.close?.();
    }
  } 
  
}

在vue中使用,新建一个websocket.vue文件:

<template>
  <div style="position: relative" />
</template>

<script>
// import urlConfig from '../network/request'
// import urlConfig from '../urlConfig'
// import vueEvents from "./vueEvent"
export default {
  name: 'WebSocketUtil',
  props: {
    sId: {
      type: String,
      default: ''
    }
  },
  data() {
    return {}
  },
  mounted() {
    this.initWebSocket()
  },
  destroyed: function() {
    // 离开页面生命周期函数
    this.websock.close()
  },
  methods: {
    websocketSend(websock, agentData) {
      // 加延迟是为了尽量让ws连接状态变为OPEN
      setTimeout(() => {
        console.log(websock)
        console.log(websock.OPEN)
        console.log(websock.CLOSED)
        // 添加状态判断,当为OPEN时,发送消息
        if (websock.readyState === websock.OPEN) {
          // websock.OPEN = 1
          // 发给后端的数据需要字符串化
          websock.send(JSON.stringify(agentData))
        }
        if (websock.readyState === websock.CLOSED) {
          // websock.CLOSED = 3
          console.log('websock.readyState=3')
          console.log('ws连接异常,请稍候重试')
        }
      }, 500)
    },
    initWebSocket: function() {
      console.log('AAAAAAAAA')
      // WebSocket与普通的请求所用协议有所不同,ws等同于http,wss等同于https
      // const wsUrl = urlConfig.webSocketUrl + (this.sId === '' ? '' : ('/' + this.sId))
      const wsUrl = 'ws://ip地址/websocket/httpMessage'
      console.log('urlw', wsUrl)
      // var token = sessionStorage.getItem('token')
      if(typeof (WebSocket) === 'undefined'){
      return '当前浏览器不支持websocket!!!'
      }
      this.websock = new WebSocket(wsUrl)
      this.websock.onopen = this.webSocketOnopen
      this.websock.onerror = this.webSocketOnerror
      this.websock.onmessage = this.webSocketOnmessage
      this.websock.onclose = this.webSocketOnclose
      this.websocketSend(this.websock, 'websock连接成功')
    },
    webSocketOnopen: function(e) {
      console.log('%c' + e.target.url, 'color: red; font-size: 10px')
      console.log('WebSocket连接成功')
    },
    webSocketOnerror: function(e) {
      console.log('WebSocket连接发生错误')
    },
    webSocketOnmessage(e) {
      this.sendData(e.data)
      console.log(JSON.parse(e.data))
    },
    webSocketOnclose: function(e) {
      console.log(
        '%cwebSocket:' + e.target.url + '断开连接...',
        'color: red; font-size: 10px'
      )
      console.log('connection closed (' + e.code + ')')
    },
    getWebsocket: function() {},
    sendData(mes) {
      console.log(mes)
      // 在父组件中通过@messageData的方式接受事件和参数
      this.$emit('messageData', mes)
      // vueEvents.$emit('show-td', mes)
    }
  }
}