一、安装sockjs-client包、stompjs包
npm install sockjs-client stompjs -save
二、sock.js文件
我的项目中使用vuex封装sock.js文件
import Vue from 'vue'
import Vuex from 'vuex'
import SockJS from "sockjs-client";
import Stomp from "stompjs";
import {getAccessToken} from '@/utils/auth'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
url:`${process.env.VUE_APP_BASE_API}/sockjs/?1access_token=${getAccessToken()}`,// token通过url携带
checkInterval:null,//断线重连时 检测连接是否建立成功
websocket:null,
stompClient:null, // stomp客户端对象
listenerList:[],//监听器列表,断线重连时 用于重新注册监听
},
getters: {
stompClient(state) {
return function () {
return state.stompClient;
}
}
},
mutations: {
WEBSOCKET_INIT(state,url) { // 初始化连接
if(state.stompClient==null||!state.stompClient.connected) {
if(url) state.url = url
if(state.stompClient!=null&&state.websocket.readyState=== SockJS.OPEN){ // 如果读取状态为open 断开连接后重新连接
state.stompClient.disconnect(()=>{
this.commit('WEBSOCKET_CONNECT')
})
}else if(state.stompClient!=null&&state.websocket.readyState=== SockJS.CONNECTING){ // 连接已建立
console.log("已连接")
return;
}else{ //
console.log("连接正在建立2")
this.commit('WEBSOCKET_CONNECT')
}
if(!state.checkInterval){ // 使用定时器进行循环访问建立连接
const interval=setInterval(()=>{
console.log("检测连接:"+state.websocket.readyState ,SockJS.CONNECTING)
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){ // 具体连接代码
try {
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连接
console.log(state,'~~~~~~~~',stompClient)
stompClient.connect(
{
// Authorization:`Bearer ${getAccessToken()}` // token也可在此处添加
}, //此处注意更换自己的用户名,最好以参数形式带入
frame => {// stomp连接成功回调
state.listenerList.forEach(item=>{
state.stompClient.subscribe(item.topic,item.callback)
console.log(state.stompClient.subscribe,'+++++++++++')
})
//unsubscribe()可以用来取消客户端对这个目的地destination的订阅
// stompClient.subscribe("/user/queue/message", msg => {
// // this.getData(msg);
// console.log(msg)
// });
},
err => {//第一次连接失败和连接后断开连接都会调用这个函数 此处调用重连
setTimeout(() => {
console.log(err,'errrrrr')
_this.commit('WEBSOCKET_INIT', state.url)
}, 1000)
},
);
state.stompClient = stompClient
}catch (e) {
console.log(e,'err')
}
},
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中为vue全局挂载$webscoket方法以便组件使用
import websocket from './store/soket'
Vue.prototype.$websocket = websocket;
四、组件引用
mounted(){
this.$websocket.state.stompClient.subscribe('/work/update',res=>{
// 订阅消息 处理逻辑
})
},
beforeDestroy() {
// 组件销毁 断开连接
this.$websocket.state.stompClient.unsubscribe('/work/update')
},