VUE下封装全局STOMP WebSocket及断线重连机制

最近一个后台管理项目中需要使用websocket跟服务器建立长连接,以便实时通信,一番百度查阅后,决定使用Stomp+websocket形式。网上简单的链接demo倒是很多,能真正发布到生产环境使用的却很少,尤其断线重连机制,一直没找到理想参考,于是决定自己写了,特此记录,以备查阅。本示例是全局使用的websocket,初始化成功后,可在任意页面或组件中调用,由于使用了stomp,可以基于主题订阅模式跟服务器端交互,使用起来非常方便。

在store文件夹下新建:websocket.js

import Vue from 'vue'
import Vuex from 'vuex'
import SockJS from "sockjs-client";
import Stomp from "stompjs";

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    url:'',
    checkInterval:null,//断线重连时 检测连接是否建立成功
    websocket:null,
    stompClient:null,
    listenerList:[],//监听器列表,断线重连时 用于重新注册监听
  },
  getters: {
    stompClient(state) {
      return function () {
        return state.stompClient;
      }
    }
  },
  mutations: {
    WEBSOCKET_INIT(state,url) {
      if(state.stompClient==null||!state.stompClient.connected) {
        state.url = url
        if(state.stompClient!=null&&state.websocket.readyState=== SockJS.OPEN){
          state.stompClient.disconnect(()=>{
            this.commit('WEBSOCKET_CONNECT')
          })
        }else if(state.stompClient!=null&&state.websocket.readyState=== SockJS.CONNECTING){
          console.log("连接正在建立")
          return;
        }else{
          this.commit('WEBSOCKET_CONNECT')
        }
        if(!state.checkInterval){
          const interval=setInterval(()=>{
            console.log("检测连接:"+state.websocket.readyState)
            if(state.stompClient!=null&&state.stompClient.connected){
              clearInterval(state.checkInterval)
              state.checkInterval=null
              console.log('重连成功')
            }else if(state.stompClient!=null&&state.websocket.readyState!= SockJS.CONNECTING){
              //经常会遇到websocket的状态为open 但是stompClient的状态却是未连接状态,故此处需要把连接断掉 然后重连
              state.stompClient.disconnect(()=>{
                this.commit('WEBSOCKET_CONNECT')
              })
            }
          },2000)
          state.checkInterval=interval
        }
      }else{
        console.log("连接已建立成功,不再执行")
      }
    },
    WEBSOCKET_CONNECT(state){
      const _this = this
      const websock = new SockJS(state.url);
      state.websocket=websock
      // 获取STOMP子协议的客户端对象
      const stompClient = Stomp.over(websock);
      stompClient.debug = null //关闭控制台打印
      stompClient.heartbeat.outgoing = 20000;
      stompClient.heartbeat.incoming = 0;//客户端不从服务端接收心跳包
      // 向服务器发起websocket连接
      stompClient.connect(
        {name: 'test'},  //此处注意更换自己的用户名,最好以参数形式带入
        frame => {
          console.log('链接成功!')
          state.listenerList.forEach(item=>{
            state.stompClient.subscribe(item.topic,item.callback)
          })
          //unsubscribe()可以用来取消客户端对这个目的地destination的订阅
          // stompClient.subscribe("/user/queue/message", msg => {
          //   // this.getData(msg);
          //   console.log(msg)
          // });
        },
        err => {//第一次连接失败和连接后断开连接都会调用这个函数 此处调用重连
          setTimeout(() => {
            _this.commit('WEBSOCKET_INIT', state.url)
          }, 1000)
        }
      );
      state.stompClient = stompClient
    },
    WEBSOCKET_SEND(state, p) {
      state.stompClient.send(p.topic,{},p.data);
    },
    WEBSOCKET_UNSUBSRCIBE(state,p){
      state.stompClient.unsubscribe(p)
      for(let i=0;i<state.listenerList.length;i++){
        if(state.listenerList[i].topic==p){
          state.listenerList.splice(i,1)
          console.log("解除订阅:"+p+" size:"+state.listenerList.length)
          break;
        }
      }

    }
  },
  actions: {
    WEBSOCKET_INIT({commit},url) {
      commit('WEBSOCKET_INIT',url)
    },
    WEBSOCKET_SEND({commit}, p) {
      commit('WEBSOCKET_SEND', p)
    },
    WEBSOCKET_UNSUBSRCIBE({commit}, p){
      commit('WEBSOCKET_UNSUBSRCIBE', p)
    }
  }
})

main.js添加引用

//socket
import websocket from './store/websocketStore'
Vue.prototype.$websocket = websocket;

接下来就是在任意需要的地方初始化链接,我是在用户登录成功,进入主界面后

created(){
      this.$websocket.dispatch('WEBSOCKET_INIT',"http://192.168.0.103:8084/websocket")
  },

链接初始化完成以后,就可以在任意界面或组件中注册监听主题或发送消息了,为了防止用户刷新的当前页面就需要注册监听,所以我用了个方法轮询,确认链接可用后再注册

            const _this=this
            const stompClient=this.$websocket.getters.stompClient()
            const interval=setInterval(()=>{
                if(stompClient!=null&&stompClient.connected){
                    clearInterval(interval)
                    _this.subscriptions.push(stompClient.subscribe("/user/queue/cmdListener",msg=>{
                        const result=JSON.parse(msg.body)
                        if(result.status) {
                            _this.$notify({
                                title: '成功',
                                message: '端口开放成功,请给设备上电',
                                type: 'success',
                                duration: 2000
                            })
                        }
                    }))
                    _this.subscriptions.push(stompClient.subscribe("/user/queue/registerDevice",msg=>{
                        _this.messageList.push(JSON.parse(msg.body))
                        console.log(msg.body)
                    }))
                    stompClient.send("/topic/cmd/registerDevice",{},"{cmd:\"openConnection\"}");
                }else{
                    console.log("等待连接成功")
                }
            },500)

 

  • 5
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

什么都搞点

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值