大家好,我是程序员大猩猩。
上次我们实践了,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