websocket自动重连封装
前端代码封装
javascript
复制代码
import { ref, onUnmounted } from 'vue';
interface WebSocketOptions {
url: string;
protocols?: string | string[];
reconnectTimeout?: number;
}
class WebSocketService {
private ws: WebSocket | null = null;
private callbacks: { [key: string]: Function[] } = {};
private reconnectTimeoutMs: number = 5000; // 默认5秒重连间隔
constructor(private options: WebSocketOptions) { }
public open(): void {
this.ws = new WebSocket(this.options.url, this.options.protocols)
this.ws.addEventListener('open', this.handleOpen);
this.ws.addEventListener('message', this.handleMessage);
this.ws.addEventListener('error', this.handleError);
this.ws.addEventListener('close', this.handleClose);
}
public close(isActiveClose = false): void {
if (this.ws) {
this.ws.close();
if (!isActiveClose) {
setTimeout(() => this.reconnect(), this.reconnectTimeoutMs);
}
}
}
public reconnect(): void {
this.open();
}
public on(event: 'message', callback: (data: any) => void): void;
public on(event: 'open' | 'error' | 'close', callback: () => void): void;
public on(event: string, callback: (...args: any[]) => void): void {
if (!this.callbacks[event]) {
this.callbacks[event] = [];
}
this.callbacks[event].push(callback);
}
private handleOpen = (): void => {
console.log('WebSocket连接已建立');
if (this.callbacks.open) {
this.callbacks.open.forEach((cb) => cb());
}
};
private handleMessage = (event: MessageEvent): void => {
console.log(event,"event");
const data = JSON.parse(event.data);
console.log('WebSocket接收到消息:', data);
if (this.callbacks.message) {
this.callbacks.message.forEach((cb) => cb(data));
}
};
private handleError = (error: Event): void => {
console.error('WebSocket错误:', error);
if (this.callbacks.error) {
this.callbacks.error.forEach((cb) => cb(error));
}
};
private handleClose = (): void => {
console.log('WebSocket连接已关闭');
if (this.callbacks.close) {
this.callbacks.close.forEach((cb) => cb());
if (!this.options.reconnectTimeout) {
this.reconnect();
}
}
};
public send(data: any): void {
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
this.ws.send(JSON.stringify(data));
} else {
console.warn('尝试发送消息时WebSocket未连接');
}
}
}
export default function useWebSocket(options: WebSocketOptions) {
const wsService = new WebSocketService(options);
onUnmounted(() => {
wsService.close(true);
});
return {
open: wsService.open.bind(wsService),
close: wsService.close.bind(wsService),
reconnect: wsService.reconnect.bind(wsService),
on: wsService.on.bind(wsService),
send: wsService.send.bind(wsService)
};
}
组件中使用
JavaScript
复制代码
<script setup lang="ts">
import { onMounted } from 'vue'
import useWebSocket from "@/utils/websocket";
const os = useWebSocket({ url: 'http://localhost:3000' })
const onSend = () => {
os.send({ text: '你好' })
}
onMounted(async () => {
os.open()
os.on('message', (event) => {
console.log(event, "event");
})
});
</script>
后端代码封装
javascript
复制代码
const express = require('express');
const bodyParser = require('body-parser');
const http = require('http');
const WebSocket = require('ws');
const cors = require('cors');
const app = express();
const server = http.createServer(app);
const corsOption = {
origin: 'http://localhost:8088',
methods: ['GET', 'POST', 'PUT', 'DELETE'],
allowedHeaders: ['Content-Type', 'Authorization'],
}
app.use(cors(corsOption))
// 增加请求体大小限制
app.use(bodyParser.json({ limit: '100mb' })); // 允许最多10MB的JSON数据
app.use(bodyParser.urlencoded({ limit: '100mb', extended: true }));
// 初始化 WebSocket 服务器实例
const wss = new WebSocket.Server({ server });
// 监听 WebSocket 连接事件
wss.on('connection', (ws) => {
console.log('客户端已连接');
// 监听消息
ws.on('message', (message) => {
console.log('收到消息:', JSON.parse(message));
const postMsg = {
msg: "你好"
}
// 回复客户端
ws.send(JSON.stringify(postMsg));
});
// 监听关闭事件
ws.on('close', () => {
console.log('客户端已断开连接');
});
});
// 设置 Express 路由
app.get('/', (req, res) => {
res.send('WebSocket Server Running');
});
// 启动服务器
server.listen(3000, () => {
console.log('服务器在 http://localhost:3000 运行');
});