前言
做项目的时候就遇到有一些数据是后端使用websoket实时返回的,我需要在对应的页面上拿到这个数据做处理使用,一开始是想要全部存缓存直接拿的,但是在场景上我是必须要拿到这个数据才能进行下一步,如果是存缓存我不知道什么时候拿,总不能隔一会就去拿一下,看回没回来,就想着能不能做一下监听
追加
做到后边发现;连接经常自己断开,影响后续操作,所以觉得还是要加一个心跳包去维持长连接
实现
data(){
return{
webSocket:null,
ws_heartCheck: {
vueThis: this, // vue实例
timeout: 30 * 1000, // 30秒一次心跳
timeoutObj: null, // 执行心跳的定时器
serverTimeoutObj: null, // 服务器超时定时器
reset: function () { // 重置方法
clearTimeout(this.timeoutObj);
clearTimeout(this.serverTimeoutObj);
return this;
},
start: function () { // 启动方法
this.timeoutObj && clearTimeout(this.timeoutObj);
this.serverTimeoutObj && clearTimeout(this.serverTimeoutObj);
this.timeoutObj = setTimeout(() => {
// 这里向后端发送一个心跳检测,后端收到后,会返回一个心跳回复
this.vueThis.webSocket.send("Ping");
this.serverTimeoutObj = setTimeout(() => {
// 如果超过一定时间还没重置计时器,说明websocket与后端断开了
console.log("未收到心跳检测回复");
this.vueThis.webSocket.close();
}, this.timeout);
}, this.timeout);
}
},
socketReconnectTimer: null, // 计时器对象——重连
socketReconnectLock: false, // WebSocket重连的锁
socketLeaveFlag: false, // 离开标记(解决 退出登录再登录 时出现的 多次相同推送 问题,出现的本质是多次建立了WebSocket连接)
}
}
methods:{
initWebSocket() {
this.webSocket = null
try {
//判断当前浏览器支不支持websoket
if ('WebSocket' in window) {
const env = process.env.NODE_ENV
//配置开发环境和生产环境,一般来说两个环境的地址是不一样的
const websocketUrl = env === 'development' ? process.env.VUE_APP_WEB_URL : window.document.location.host;
this.webSocket = new WebSocket('ws://' + websocketUrl + '/subscriptions')
this.socketEventBind();
} else {
this.$message.error('当前浏览器不支持 websocket')
}
} catch (e) {
//重连
this.socketReconnect();
}
},
// websocket事件绑定
socketEventBind() {
//连接成功回调
this.webSocket.onopen = this.webSocketOnOpen
//消息接收
this.webSocket.onmessage = this.webSocketOnMessage
//连接错误
this.webSocket.onerror = this.webSocketOnError
//连接关闭
this.webSocket.onclose = this.webSocketOnClose
//监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
window.onbeforeunload = () => {
this.webSocket.close();
};
},
// websocket重连
socketReconnect() {
if (this.socketReconnectLock) {
return;
}
this.socketReconnectLock = true;
this.socketReconnectTimer && clearTimeout(this.socketReconnectTimer);
this.socketReconnectTimer = setTimeout(() => {
console.log("WebSocket:重连中...");
this.socketReconnectLock = false;
// websocket启动
this.initWebSocket();
}, 4000);
},
webSocketOnOpen() {
console.log('---连接建立成功---')
this.ws_heartCheck.reset().start();
this.websocketsend(JSON.stringify({
query: `subscription {
sessionEvent(sessionId: "${this.sessionId}") {
type
message
}
}`}))
},
closeWs() {
this.webSocket.close();
},
webSocketOnError() {
console.log("WebSocket:发生错误");
this.socketReconnect();
},
webSocketOnMessage(e) {
if (e.data.indexOf("Pong") > -1) {
this.ws_heartCheck.reset().start();
} else {
// 数据接收
this.redata = JSON.parse(e.data)
const webSocketInfo = this.webSocketInfo
window.dispatchEvent(new CustomEvent('onmessageWS', {
detail: {
data: { [this.redata.data.sessionEvent.type]: this.redata.data.sessionEvent.message }
}
}))
}
},
websocketsend(Data) {
// 数据发送
this.webSocket.send(Data)
},
webSocketOnClose(e) {
console.log('websocket 断开')
this.ws_heartCheck.reset();
if (!this.socketLeaveFlag) {
this.socketReconnect();
}
},
}
在需要使用的页面监听事件 mounted(){ window.addEventListener('onmessageWS', (res)=>{ //res就是传过来的数据res.detail就可以拿到了 }) }