websocket自动重连封装

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 运行');
});
相关推荐
To_OC7 小时前
别再串行写 await 了,Promise.all 才是并行请求的正确打开方式
前端·javascript·promise
vipbic8 小时前
中后台越做越乱后,我用插件化把它救回来了
前端·vue.js
Hyyy8 小时前
Computer Use 适合做什么,不适合做什么——一次真实使用后的思考
前端
小和尚同志8 小时前
前端 AI 单元测试思考与落地
前端·人工智能·aigc
invicinble9 小时前
c端系统,其实更像一个信息展示平台
前端
李姆斯10 小时前
管理是否可以被完全量化
前端·产品经理·团队管理
名字还没想好☜11 小时前
Next.js 中间件实战:鉴权、重定向与 A/B 分流
开发语言·前端·javascript·中间件·react·next.js
广州灵眸科技有限公司11 小时前
瑞芯微RV1126B开发板(EASY-EAI-PI2) INI文件操作
java·前端·javascript·网络·人工智能
kaiking_g11 小时前
vue项目中,静态导入 vs 动态导入 详解
前端·javascript·vue.js
江华森11 小时前
Web 开发基础:HTTP 与 REST
前端·网络协议·http