WebSocket是一种在Web浏览器和Web服务器之间创建持久性连接的通信协议。它允许客户端和服务器之间进行全双工通信,这意味着服务器可以主动向客户端发送数据,而不需要客户端首先发起请求。通常用于实时数据传输的场景
在vue项目中使用 WebSocket,可以选择第三方库,也可以使用浏览器原生的 WebSocket API,这里仅介绍原生API的使用
------------------------------------------------------------------------------------------------------------------------------------------
简单的 demo
javaScript
// YourComponent.vue
export default {
data() {
return {
socket: null
};
},
mounted() {
// 初始化WebSocket连接
this.socket = new WebSocket('ws://your-websocket-server-url');
// 监听WebSocket事件
this.socket.onopen = () => {
console.log('WebSocket connected');
};
this.socket.onmessage = (event) => {
console.log('Received message:', event.data);
// 处理接收到的消息
};
// 其他事件监听和处理,如 this.socket.onclose, this.socket.onerror
// 如果需要发送消息,可以调用 this.socket.send()
},
beforeDestroy() {
// 在组件销毁前关闭WebSocket连接
if (this.socket) {
this.socket.close();
}
}
};
- 上面 demo 使用
new WebSocket('ws://your-websocket-server-url')
来创建WebSocket实例,然后使用this.socket.onopen
、this.socket.onmessage
等事件处理函数来监听WebSocket的连接、接收消息等事件 - 在组件销毁前,使用
this.socket.close()
来关闭WebSocket连接
封装一个 Socket 类
javaScript
import EventBus from '@/eventBus';
class Socket {
constructor() {
// 基础URL
this.baseUrl = `${window.location.protocol === 'https:' ? 'wss' : 'ws'}://${window.location.host}`;
// 最终的URL
this.webSocketUrl = null;
// webSocket实例
this.ws = null;
// 重连timeId
this.reconnectTimer = 0;
// 重连主动触发timeId
this.emitReconnectTimer = 0;
// 心跳timeId
this.heartBeatTimer = 0;
// 心跳失效关闭定时器
this.receiverTimer = 0;
// 暂存消息
this.cacheMessage = [];
}
/**
* 初始化
* @param url websocket url
*/
init(url) {
if ('WebSocket' in window) {
if (url) {
this.webSocketUrl = `${this.baseUrl}${url}`;
}
this.ws = new WebSocket(this.webSocketUrl);
this._bindListeners();
} else {
console.log('你的浏览器不支持WebSocket');
}
}
/**
* 手动关闭
*/
close() {
if (this.ws) {
this.clearHeartBeat();
this.ws.close();
}
}
/**
* 判断webSocket是否已连接
* @returns {null|boolean}
*/
ready() {
return this.ws && this.ws.readyState === WebSocket.OPEN;
}
/**
* 发送消息
* @param message
*/
sendMessage(message) {
if (this.ready()) {
this.ws.send(JSON.stringify(message));
} else {
this.cacheMessage.push(message);
}
}
/**
* 心跳机制
*/
heartBeat() {
this.clearHeartBeat();
this.heartBeatTimer = setTimeout(() => {
this.ws.send('ping');
this.receiverTimer = setTimeout(() => {
this.close();
}, 20000);
}, 20000);
}
/**
* 清理心跳
*/
clearHeartBeat() {
if (this.heartBeatTimer) {
clearTimeout(this.heartBeatTimer);
this.heartBeatTimer = 0;
}
if (this.receiverTimer) {
clearTimeout(this.receiverTimer);
this.receiverTimer = 0;
}
}
/**
* 重连
*/
reconnect() {
this.destroyed();
if (this.reconnectTimer) {
clearTimeout(this.reconnectTimer);
this.reconnectTimer = 0;
}
if (this.emitReconnectTimer) {
clearTimeout(this.emitReconnectTimer);
this.emitReconnectTimer = 0;
}
this.reconnectTimer = setTimeout(() => {
this.init();
// 重连后主动触发相应请求
this.emitReconnectTimer = setTimeout(() => {
EventBus.$emit('reconnect');
}, 1000);
}, 2000);
}
/**
* 销毁webSocket
*/
destroyed() {
if (this.ws) {
this.clearHeartBeat();
this._unbindListeners();
if (this.ready()) {
this.ws.close();
}
this.ws = null;
}
}
/**
* 监听webSocket
* @private
*/
_bindListeners() {
this.ws.onopen = e => {
console.log('WebSocket onopen');
this.heartBeat();
if (this.cacheMessage && this.cacheMessage.length) {
this.cacheMessage.forEach(message => {
this.sendMessage(message);
});
this.cacheMessage = [];
}
};
this.ws.onmessage = e => {
if (e.data === 'pong') {
this.clearHeartBeat();
this.heartBeat();
} else {
const data = JSON.parse(e.data);
// 此处就可以对接受的数据进行处理
// 可以通过
}
};
this.ws.onclose = e => {
console.log('WebSocket onclose', e);
this.reconnect();
};
this.ws.onerror = e => {
console.log('WebSocket onerror', e);
this.reconnect();
};
}
/**
* 解除绑定
* @private
*/
_unbindListeners() {
this.ws.onopen = null;
this.ws.onmessage = null;
this.ws.onclose = null;
this.ws.onerror = null;
}
}
export default new Socket();
在组件中使用
javaScript
<script>
import Socket from '@/socket';
export default {
name: 'index',
created() {
Socket.init('/api/dac/sembi/websocket/growthBoard/realtime');
},
destroyed() {
Socket.destroyed();
}
};
</script>
- 组件中引入后,可以通过 Socket.sendMessage 发送信息
- 组件接收信息的方就是用 EventBus,通过创建一个新的Vue实例并将其用作事件总线来实现EventBus的功能
javaScript
import Vue from 'vue';
export default new Vue();
- 然后在Socket接收信息后,通过 EventBus. <math xmlns="http://www.w3.org/1998/Math/MathML"> e m i t 触发一个事件,在组件里通过 E v e n t B u s . emit 触发一个事件,在组件里通过 EventBus. </math>emit触发一个事件,在组件里通过EventBus.on 监听一个事件,比如上面Socket重连时,通过
EventBus.$emit('reconnect');
告诉组件Socket重连了