实用实例
vue3-案例2
import { createApp } from 'vue';
import { createWebSocket } from 'ws';
// 创建一个工具类
class WebSocketUtil {
constructor() {
this.ws = null;
}
// 连接WebSocket服务器
connect(url) {
if (this.ws && this.ws.readyState === ws.OPEN) {
console.log('WebSocket已经连接');
} else {
this.ws = createWebSocket(url);
const onOpen = () => {
console.log('WebSocket连接成功');
};
const onMessage = (event) => {
console.log('收到消息:', event.data);
};
const onClose = (event) => {
console.log('WebSocket连接关闭', event);
};
const onError = (error) => {
console.error('WebSocket连接错误', error);
};
this.ws.onopen = onOpen;
this.ws.onmessage = onMessage;
this.ws.onclose = onClose;
this.ws.onerror = onError;
}
}
// 发送消息到WebSocket服务器
send(message) {
if (this.ws && this.ws.readyState === ws.OPEN) {
this.ws.send(message);
} else {
console.error('WebSocket未连接或已关闭');
}
}
// 关闭WebSocket连接
close() {
if (this.ws) {
this.ws.close();
} else {
console.error('WebSocket未连接');
}
}
}
// 在Vue3中使用工具类
const app = createApp({});
app.provide('websocketUtil', new WebSocketUtil()); // 将工具类注入到Vue实例中,方便在组件中使用。
app.mount('#app'); // 在HTML中使用组件时需要指定id为app。例如:<websocket-util></websocket-util>。
vue3
安装依赖
npm install ws --save
封装Websocket类
import WebSocket from 'ws';
class Websocket {
constructor(url, options = {}) {
this.url = url;
this.options = options;
this.ws = null;
}
connect() {
this.ws = new WebSocket(this.url, this.options);
this.ws.onopen = () => {
console.log('Websocket connection opened.');
};
this.ws.onmessage = (event) => {
console.log('Websocket message received.', event.data);
};
this.ws.onerror = (error) => {
console.error('Websocket error occurred.', error);
};
this.ws.onclose = () => {
console.log('Websocket connection closed.');
};
}
send(data) {
if (this.ws.readyState === WebSocket.OPEN) {
this.ws.send(data);
} else {
console.error('Websocket connection not open.');
}
}
close() {
this.ws.close();
}
}
export default Websocket;
vue-native-websocket(vue3)
参阅文献:https://juejin.cn/post/7236992165745180728
npm install vue-native-websocket
import { ref, onMounted, onUnmounted } from 'vue';
import { useWebSocket } from 'vue-native-websocket';
export default {
setup() {
const socket = useWebSocket('wss://xxxx/socket');
// 监听连接事件
onMounted(() => {
socket.value.onopen = () => {
console.log('WebSocket connected');
};
});
// 监听消息事件
const message = ref('');
socket.value.onmessage = (event) => {
message.value = event.data;
};
// 监听关闭事件
onUnmounted(() => {
socket.value.onclose = () => {
console.log('WebSocket disconnected');
};
});
return {
message,
};
},
};
// 发送消息
socket.value.send('Hello, server!');
// 连接错误,如果连接失败,可以通过 `onerror` 事件处理错误,并将错误信息打印到控制台。
socket.value.onerror = (event) => {
console.error('WebSocket error:', event);
};
// 重新连接,如果 WebSocket 连接断开,可以通过重新创建 WebSocket 实例来重新连接。
// 通过 `onclose` 事件监听连接关闭,并在连接关闭时重新创建 WebSocket实例来重新连接。
socket.value.onclose = () => {
console.log('WebSocket disconnected');
// 重新连接
socket.value = useWebSocket('wss://example.com/socket');
};
心跳机制
为了保持 WebSocket 连接的活跃状态,可以使用心跳机制定期发送心跳消息。
ini复制代码// 心跳消息
const heartbeatMessage = 'ping';
// 定时发送心跳消息
setInterval(() => {
socket.value.send(heartbeatMessage);
}, 5000);
// 监听消息事件
socket.value.onmessage = (event) => {
const message = event.data;
if (message === heartbeatMessage) {
// 收到心跳消息,做相应处理
} else {
// 处理其他消息
}
};
// store/modules/websocket.js
const state = {
socket: null,
message: '',
};
const mutations = {
SET_SOCKET(state, socket) {
state.socket = socket;
},
SET_MESSAGE(state, message) {
state.message = message;
},
};
const actions = {
connect({ commit }) {
const socket = useWebSocket('wss://xxxxx/socket');
socket.value.onopen = () => {
console.log('WebSocket connected');
};
socket.value.onmessage = (event) => {
commit('SET_MESSAGE', event.data);
};
socket.value.onclose = () => {
console.log('WebSocket disconnected');
};
commit('SET_SOCKET', socket);
},
sendMessage({ state }, message) {
state.socket.value.send(message);
},
};
export default {
state,
mutations,
actions,
};
然后,在主 store
文件中导入和注册该模块。
// store/index.js
import { createStore } from 'vuex';
import websocket from './modules/websocket';
export default createStore({
modules: {
websocket,
},
});
现在,可以在组件中使用 mapState
和 mapActions
辅助函数来访问 WebSocket 的状态和发送消息。
<template>
<div>
<p>Message: {{ message }}</p>
<button @click="sendMessage">Send Message</button>
</div>
</template>
<script>
import { mapState, mapActions } from 'vuex';
export default {
computed: {
...mapState('websocket', ['message']),
},
methods: {
...mapActions('websocket', ['connect', 'sendMessage']),
},
mounted() {
this.connect();
},
};
</script>
使用 mapState
辅助函数将 websocket
模块的 message
状态映射到组件的计算属性,使用 mapActions
辅助函数将 websocket
模块的 connect
和 sendMessage
方法映射到组件的方法。在组件的 mounted
钩子中调用 connect
方法来建立 WebSocket 连接。
常见问题处理
1. 跨域问题
当使用 WebSocket 连接到不同域的服务器时,可能会遇到跨域问题。为了解决这个问题,服务器需要设置适当的 CORS 头部。
2. 断线重连
在 WebSocket 连接断开的情况下,可以通过在 onclose
事件中重新建立连接来实现断线重连。
socket.value.onclose = ()=> {
setTimeout(() => {
connect();
}, 3000);
};
使用 setTimeout
函数在连接断开后等待 3 秒钟重新建立连接。
3. 消息队列和缓存
在网络不稳定或连接断开的情况下,可能会导致消息丢失。为了解决这个问题,可以使用消息队列和缓存机制来保证消息的可靠传输和持久化存储。
在 Vuex 中,可以使用数组来作为消息队列,并在连接恢复后重新发送未发送的消息。
const state = {
socket: null,
messageQueue: [],
};
const actions = {
sendMessage({ state }, message) {
if (state.socket.value.readyState === WebSocket.OPEN) {
state.socket.value.send(message);
} else {
state.messageQueue.push(message);
}
},
reconnect({ state, dispatch }) {
if (state.socket.value.readyState === WebSocket.CLOSED) {
dispatch('connect');
state.messageQueue.forEach((message) => {
dispatch('sendMessage', message);
});
state.messageQueue = [];
}
},
};
使用 messageQueue
数组来存储未发送的消息。在发送消息时,如果 WebSocket 连接处于打开状态,直接发送消息;否则,将消息添加到消息队列中。在重新连接时,遍历消息队列并重新发送未发送的消息。
4. 心跳检测
在 WebSocket 连接中,由于网络波动或其他原因,连接可能会在一段时间内变得不活跃。为了保持连接的稳定性,可以使用心跳检测机制来定期发送心跳消息,以确保连接保持活跃。
javascript复制代码const PING_INTERVAL = 5000; // 心跳间隔,单位为毫秒
const actions = {
connect({ commit, dispatch }) {
const socket = useWebSocket('wss://example.com/socket');
socket.value.onopen = () => {
console.log('WebSocket connected');
// 启动心跳检测
setInterval(() => {
dispatch('sendHeartbeat');
}, PING_INTERVAL);
};
// ...
},
sendHeartbeat({ state }) {
if (state.socket.value.readyState === WebSocket.OPEN) {
state.socket.value.send('ping');
}
},
};
在上面的例子中,在连接建立后启动了一个定时器,定期发送心跳消息("ping")。通过定期发送心跳消息,可以确保连接保持活跃,并在一段时间内检测到连接断开的情况。
5. 错误处理
在使用 WebSocket 过程中,可能会出现各种错误,如连接错误、消息发送失败等。为了处理这些错误,可以在相应的事件处理程序中进行错误处理。
ini复制代码socket.value.onerror = (error) => {
console.error('WebSocket error:', error);
};
socket.value.onmessage = (event) => {
// 处理接收到的消息
};
socket.value.onclose = (event) => {
if (event.code === 1006) {
console.error('WebSocket connection closed unexpectedly');
} else {
console.log('WebSocket disconnected');
}
};
在 onerror
事件处理程序中打印错误信息,并在 onclose
事件处理程序中根据关闭代码进行适当的错误处理。
6. 清理和销毁
在 Vue 3 中,组件销毁时,需要确保关闭 WebSocket 连接以及清理相关资源,以避免内存泄漏和不必要的网络连接。
javascript复制代码import { onBeforeUnmount } from 'vue';
export default {
setup() {
const socket = useWebSocket('wss://example.com/socket');
// ...
onBeforeUnmount(() => {
if (socket.value && socket.value.readyState === WebSocket.OPEN) {
socket.value.close();
}
});
// ...
},
};
使用 onBeforeUnmount
钩子函数来监听组件销毁前的事件,并在该事件触发时关闭 WebSocket 连接。