微服务使用SockJs+Stomp实现Websocket 前后端实例 | Vuex形式断开重连、跨域等等问题踩坑(二)

大家好,我是程序员大猩猩。

上次我们实践了,Java后端如何完成SockJS+Stomp的配置实现。

微服务使用SockJs+Stomp实现Websocket 前后端实例 | Vuex形式断开重连、跨域等等问题踩坑(一)

那么今天我们做一下web vue端的是如何来实现的。

这里我罗列一下,我实现所使用的vue版本。

"sockjs-client": "^1.5.0",
"stompjs": "^2.3.3",
"vue": "^3.0.0",
"vuex": "^4.1.0"
// 本地Node版本号
node v14.21.3

这里,我从创建好工程后,导入工程开始说起,说说我碰到的问题及我的解决方法,一遍大家更好的理解。

首先,我是采用vue create *** 来创建一个项目,中间选择使用vuex组件。待项目创建后,我这里使用WebStorm开发工具,将项目导入后,工具会自动让我们npm install。

在项目的根目录

npm install sockjs-client
npm install stompjs

或者

package.json->dependencies->下添加

"sockjs-client": "^1.5.0",
"stompjs": "^2.3.3",

因为我们是需要在vuex中实现SockJs的,所以在src内创建store目录,并且完成一下代码store/index.js

import modules from './modules'

import { createStore } from 'vuex'
export default new createStore({
  modules,
  strict: false
})

在store目录下创建modules文件目录,目录内新增index.js和websocket.js

// index.js

const files = require.context('.', false, /\.js$/)
const modules = {}

files.keys().forEach(key => {
    if (key === './index.js') return
    modules[key.replace(/(\.\/|\.js)/g, '')] = files(key).default
})

export default modules

// websocket.js

import {createStore} from 'vuex'
import SockJS from 'sockjs-client'
import Stomp from 'stompjs'
import config from '../../config/index'
// 后端ws连接 http开头形式
const url = config.scokJsUrl

​​​​​​​接下来我们分析一下,websocket在前端需要什么操作呢?

1. 初始化

WEBSOCKET_INIT({
                   commit,
                   state
               }, header) {
    commit('WEBSOCKET_INIT', header)
},

​​​​​​​

2. 发送消息

WEBSOCKET_SEND({
                   commit,
                   state
               }, p) {
    commit('WEBSOCKET_SEND', p)
},

​​​​​​​

3. 订阅

WEBSOCKET_UNSUBSRCIBE({
                          commit,
                          state
                      }, p) {
    commit('WEBSOCKET_UNSUBSRCIBE', p)
},

4. 断开

WEBSOCKET_DISCONNECT({
                         commit,
                         state
                     }) {
    commit('WEBSOCKET_DISCONNECT')
}

​​​​​​​我们在store注册actions,actions注册以上方法。然后在mutations内实现以上方法。

 mutations: {
    WEBSOCKET_INIT(state, header) {
        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', header)
                })
            } else if (state.stompClient != null && state.websocket.readyState === SockJS.CONNECTING) {
                console.log('连接正在建立')
                return
            } else {
                this.commit('WEBSOCKET_CONNECT', header)
            }
            // 断线重连实现块
            // 断线重连实现块
            // 断线重连实现块
            // 断线重连实现块
        } else {
            console.log('连接已建立成功,不再执行')
        }
    },
    WEBSOCKET_CONNECT(state, header) {
        const _this = this
        console.log('URL链接 ' + state.url)
        const websock = new SockJS(state.url)
        console.log('URL链接 ' + websock)
        state.websocket = websock
        // 获取STOMP子协议的客户端对象
        const stompClient = Stomp.over(websock)
        stompClient.connect(header,
            () => {
                console.log('链接成功!')
                state.listenerList.forEach(item => {
                    state.stompClient.subscribe(item.topic, item.callback, header)
                })
            },
            (err) => {
                console.log('链接失败!', err)
                // 第一次连接失败和连接后断开连接都会调用这个函数 此处调用重连
                setTimeout(() => {
                    _this.commit('WEBSOCKET_INIT', header)
                }, 1000)
            }
        )
        state.stompClient = stompClient
    },
    WEBSOCKET_SEND(state, p) {
        state.stompClient.send(p.topic, {userId: p.userId}, 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
            }
        }
    },
    WEBSOCKET_DISCONNECT(state) {
        if (state.stompClient != null) {
            console.log('关闭连接')
            state.stompClient.disconnect()
        }
    }
},

​​​​​​​sockJs主要连接代码为WEBSOCKET_CONNECT内:

const websock = new SockJS(state.url)
console.log('URL链接 ' + websock)
state.websocket = websock
// 获取STOMP子协议的客户端对象
const stompClient = Stomp.over(websock)

    当websocket.js实现完成后,我们也基本完成的vue端的实现,接下来在现实端页面,调用vuex即可。参考我的methods

methods: {
  disconnect() {
    clearInterval(this.connectionTimer);
    clearInterval(this.timer);
    this.$websocket.dispatch("WEBSOCKET_DISCONNECT");
  },
  stompConnection() {
    const loginUserId = "my you Dad";
    const headers = {
      token: "SSSRIRTOKEN326458",
      userId: loginUserId
    };
    this.$websocket.dispatch("WEBSOCKET_INIT", headers);

    const _this = this;
    const stompClient = this.$websocket.getters.stompClient();
    this.connectionTimer = setInterval(() => {
      if (stompClient != null && stompClient.connected) {
        clearInterval(this.connectionTimer);
        _this.subscriptions = [];
        _this.subscriptions.push(stompClient.subscribe("/user/" + loginUserId + "/queue/ping", msg => {
          console.log("我要的ping信息" + msg.body);
        }));
        // 定时推送订阅信息
        this.timer = setInterval(function () {
          const header = {
            userId: loginUserId
          };
          stompClient.send("/ping", header, "ping");
        }, 10000);
      } else {
        console.log("等待连接成功");
      }
    }, 500);
  }
}

​​​​​​​前后端一起启动项目,查看结果。

图片

StompJS的一些设置:

// 关闭控制台打印
// stompClient.debug = null
// stompClient.heartbeat.outgoing = 20000
// // 客户端不从服务端接收心跳包
// stompClient.heartbeat.incoming = 0

​​​​​​​

上一篇:onion洋葱模型


下一篇:视频输入c++ 调用 libtorch推理