Skip to main content

实用实例

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,
},
});

现在,可以在组件中使用 mapStatemapActions 辅助函数来访问 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 模块的 connectsendMessage 方法映射到组件的方法。在组件的 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 连接。