vue项目使用websocket连接问题及解决

2022-10-10 11:40:06

目录vue使用websocket连接前景解决过程vue2全局使用websocket记录新建ws模块文件在main.js中引用ws模块文件App.vue挂载时再次连接服务器并且接收消息vue使用webs...

目录
vue使用websocket连接
前景 
解决过程
vue2全局使用websocket记录
新建ws模块文件
在main.js中引用ws模块文件
App.vue挂载时再次连接服务器并且接收消息

vue使用websocket连接

前景 

公司做一个包含websocket的项目,我用的是vue做的,开始只有一个组件的要求demo,就将websocket的配置直接放在组件方法中,组件挂载时直接初始化ws,但是后续组件增加,开始出现多个websocket链接的情况,是不允许的。

刚开始的做法是将websocket的方法配置等封装为一个js文件给各个组件调用,当离开组件页面进入新页面时会断连旧的ws新建一个ws,以为做到了独立,但是实际上确实多次的断连链接,十分不便。

思考了挺久找到了解决方法www.cppcns.com,在此记录加深记忆

解决过程

要求整个vue项目使用一个ws链接,在各组件都要求可以接受发送消息

首先想到的就是在app.vue下创建我是链接,然后给各个小的组件使用ws,做到统一,很简单的解决思路,我是这么做的

前期已经将ws封装成一个wsconnect.js文件了,那么是否可以将wsconnect注册为全局的方法呢,试了一下果真可行,只需要在main.js中配置:

import wsConnect from "@/assets/js/wsConnect";
Vue.prototype.$ws = wsConnect

new Vue({
 render: h => h(App),
 router,
 axIOS,
 store
}).$mount('#app')

说明一下,在wsconnect.js文件中我封装了方法,但是把ws对象放在了vuex的state中,相关配置如下:

wsconnect.js:

import axios from "axios";
import store from "@/store";

//websocket

function initWebpack(){
  var url = store.state.url
  var wsurl = ''
  axios.get(`${url}/bcall/url`) //这是我在从后端拿ws链接的地址
    .then((res) => {
      console.log(res.data.data)
      wsurl = res.data.data
      store.state.ws = new WebSocket(wsurl);
      store.state.ws.onopen = onopen;
      store.state.ws.onmessage = onmessage;
      store.state.ws.onclose = onclose;
      store.state.ws.onerror = onerror;

    }).catch((err)=> {
    console.log(err)
  })

}
function onopen() {
  console.log("连接websocket");
  var params = '{"reqtype":"Query","action":"allexts"}'
  store.state.ws.send(params)
  start();
}
function reconnect() {//重新连接
  var that = store.state;
  if(that.lockReconnect) {
    return;
  }
  that.lockReconnect = true;
  //没连接上会一直重连,设置延迟避免请求过多
  that.timeoutnum && clearTimeout(that.timeoutnum);
  that.timeoutnum = setTimeout(function () {
    //新连接
    initWebpack();
    that.lockReconnect = false;
    that.isFirstGet = true
  },5000);
}
function reset(){//重置心跳
  var that = store.state;
  //清除时间
  clearTimeout(that.timeoutObj);
  clearTimeout(that.serverTimeoutObj);
  //重启心跳
  start();
}
function start(){ //开启心跳
  console.log('开启心跳');
  var self = store.state;
  self.timeoutObj && clearTimeout(self.timeoutObj);
  self.serverTimeoutObj && clearTimeout(self.serverTimeoutObj);
  self.timeoutObj = setTimeout(function(){
    //这里发送一个心跳,后端收到后,返回一个心跳消息,
    if (self.ws.readyState === 1) {//如果连接正常
     
      self.ws.send(heartbeat); //心跳包格式需要自己确定

    }else{//否则重连
      reconnect();
    }
    self.serverTimeoutObj = setTimeout(function() {
      //超时关闭
      self.ws.close();
      reconnect()
    }, self.timeout);
  }, self.timeout)
}
function onmessage(e) {
  console.log('接收数据',e)
  //处理数据的地方
  reset();
}
function onclose(e) {
  console.log('websocket 断开: ',e);

}
function onerror(e) {
  console.log("出现错误");
  //重连
  reconnect();
}


export default {
  initWebpack,
  onmessage,
  onclose,
  onopen,
  onerror
}

store.state:

state: {
    permissions: false,
    url: '',
    //ws参数
    path: '',
    ws: null,//建立的连接
    lockReconnect: false,//是否真正建立连接
    timeout: 58*1000,//58秒一次心跳
    timeoutObj: null,//心跳心跳倒计时
    serverTimeoutObj: null,//心跳倒计时
    timeoutnum: null,//断开 重连倒计时

  },

配置之后我在app.vue挂载之后直接初始化ws链接:

mounted() {
  this.$ws.initWebpack()
 }

发现是成功的,已经将ws链接上了,接着就是在各个组件测试一下发送数据的功能:

this.$store.state.ws.send(msg)

神奇的发现,也成功了!

之所以这么简单,前期的封装也是占功劳的嘛,至此我的vue只需要一个ws链接就可以供整个项目使用,虽然不知道别人的做法是怎么样,如果有更好的方法也希望大家讲解下

vue2全局使用websocket记录

1、考虑到登录之后要始终连接服务器接收消息,所以把websocket实例对象作为模块抛出,在main.js中引入,使全局都可以获得ws并且使用相关方法。

2、由于刷新页面时,ws会自动断开连接,所以在App.vue组件挂载时再次连接服务器。

新建ws模块文件

该文件位置任意,引入的时候注意路径即可

export default {
  ws: {},
  setWs: function(newWs) {
    this.ws = newWs
  },
  start(){// 发送心跳
    clearInterval(this.timeoutObj)
    this.timeoutObj = setInterval(() => {
      if (this.ws && this.ws.readyState == 1) {
        console.log('发送心跳')
        this.ws.send(JSON.stringify({
          //后端需要接收的数据
        }));
      }
    }, 10 *1000)//十秒发一次
  },
  localSocket(userId) {//连接ws,根据连接服务器是否需要参数设置该方法是否需要接收参数
    if ("WebSocket" in window) {
      // console.log("您的浏览器支持 WebSocket!");
      // location.host
      this.ws = new WebSocket('这里要填连接服务器的地址');
      this.setWs(this.ws);
      this.ws.onopen = ()=>{
        console.log('websocket连接成功');
        //连接上之后要发心跳包
        this.start()
      };
      this.ws.onclose = function () {
        // 关闭 websocket
        console.log("连接已关闭...");
        //断线重新连接
        setTimeout(() => {
          this.localSocket(userId);
        }, 2000);
      };
    } else {
      // 浏览器不支持 WebSocket
      console.log("您的浏览器不支持 WebSocket!");
      this.openNotificationWithIcon('error', '浏览器', '您的浏览器不支持显示消息请更换', 1,1)
    }
  },
}

在main.js中引用ws模块文件

import global from './ws.js'
Vue.prototype.global = global

App.vue挂载时再次连接服务器并且接收消息

mounted(){
   this.global.localSocket(userId)
   //连上之后要接收服务器发来的消息
   this.global.ws.onmessage = (msg)=>{
     console.log(JSON.parse(msg.data))
   }
}

通过以上方法,任何组件都可以通过this.global.ws获得websocket实例对象并且使用相关方法,可能会有些问题,但是我别的问题太多了,这个先放一下吧。 

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。