ivan135 / learn-blog

0 stars 0 forks source link

websocket在vue的应用 #7

Open ivan135 opened 4 years ago

ivan135 commented 4 years ago

项目的需求

在项目需要在局域网中,电脑网页和电话实时连接,当收到订单时,网页会有提示

选择websocket的原因

假如使用setInterval轮询接口,需要客户端定时向服务器发送ajax请求,服务器接到请求后返回响应信息。这就需要大量的占据服务器资源。同时在HTTP1.x协议中也存在一些比如线头阻塞、头部冗余等问题

而使用websocket的话,建立在 TCP 协议之上,数据格式比较轻量,性能开销小,通信高效,可以发送文本,也可以发送二进制数据。同时它还没有同源限制,客户端可以与任意服务器通信。

websocket使用心跳重连

在某些场景下使用websocket的时候,如果设备网络断开,不会立刻触发websocket的任何事件,前端也就无法得知当前连接是否已经断开。这个时候如果调用websocket.send方法,浏览器才会发现链接断开了,便会立刻或者一定短时间后,触发onclose函数。

后端websocket服务也可能出现异常,造成连接断开,这时前端也并没有收到断开通知,因此需要前端定时发送心跳消息ping,后端收到ping类型的消息,立马返回pong消息,告知前端连接正常。如果一定时间没收到pong消息,就说明连接不正常,前端便会执行重连。

为了解决以上两个问题,以前端作为主动方,定时发送ping消息,用于检测网络和前后端连接问题。一旦发现异常,前端持续执行重连逻辑,直到重连成功。

代码实现


export default {
  data() {
    return {
      websock: null,//建立的连接
      lockReconnect: false,//是否真正建立连接
      timeout: 30*1000,//30秒一次心跳
      timeoutObj: null,//心跳心跳倒计时
      serverTimeoutObj: null,//心跳倒计时
      timeoutnum: null,//断开 重连倒计时
    };
  },
  created() {
    //页面刚进入时初始化长连接
    this.initWebSocket();
  },
  destroyed: function() {
    //页面销毁时关闭长连接
    this.websocketclose();
  },
  methods: {
    initWebSocket(){//建立连接
      //初始化weosocket
      //const wsuri = "ws://sms.填写您的地址.com/websocket/" //ws地址
      const wsuri = ""
      //建立连接
      this.websock = new WebSocket(wsuri);
      //连接成功
      this.websock.onopen = this.websocketonopen;
      //连接错误
      this.websock.onerror = this.websocketonerror;
      //接收信息
      this.websock.onmessage = this.websocketonmessage;
      //连接关闭
      this.websock.onclose = this.websocketclose;
    },
    reconnect() {//重新连接
      var that = this;
      if(that.lockReconnect) {
        return;
      };
      that.lockReconnect = true;
      //没连接上会一直重连,设置延迟避免请求过多
      that.timeoutnum && clearTimeout(that.timeoutnum);
      that.timeoutnum = setTimeout(function () {
        //新连接
        that.initWebSocket();
        that.lockReconnect = false;
      },5000);
    },
    heartCheckReset(){//重置心跳
      var that = this;
      //清除时间
      clearTimeout(that.timeoutObj);
      clearTimeout(that.serverTimeoutObj);
      //重启心跳
      that.heartCheckStart();
    },
    heartCheckStart(){//开启心跳
      var self = this;
      self.timeoutObj && clearTimeout(self.timeoutObj);
      self.serverTimeoutObj && clearTimeout(self.serverTimeoutObj);
      self.timeoutObj = setTimeout(function(){
        //这里发送一个心跳,后端收到后,返回一个心跳消息,
        if (self.websock.readyState == 1) {//如果连接正常
          self.websock.send("heartCheck");
        }else{//否则重连
          self.reconnect();
        }
        self.serverTimeoutObj = setTimeout(function() {
          //超时关闭
          self.websock.close();
        }, self.timeout);

      }, self.timeout)
    },
    websocketonopen() {//连接成功事件
      //提示成功
      s.success("连接成功",3)
      //开启心跳
      this.heartCheckStart();
    },

    websocketonerror(e) {//连接失败事件
      //错误
      console.log("WebSocket连接发生错误");
      //错误提示
      s.error("Websocket error, Check you internet!")
      //重连
      this.reconnect();
    },
    websocketclose(e) {//连接关闭事件
      //关闭
      console.log("connection closed (" + e.code + ")");
      //提示关闭
      s.error("连接已关闭",3);
      //重连
      this.reconnect();
    },
    websocketonmessage(event) {//接收服务器推送的信息
      //打印收到服务器的内容
      console.log(event.data);
      //收到服务器信息,心跳重置
      this.heartCheckReset();
    },
    websocketsend(msg) {//向服务器发送信息
      //数据发送
      this.websock.send(msg);
    },
  }
};