当前位置: 首页 > article >正文

websocket自动重连封装

websocket自动重连封装

前端代码封装

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

组件中使用

<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>

后端代码封装

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 运行');
});


http://www.kler.cn/a/535795.html

相关文章:

  • Windows 中学习Docker环境准备2、Docker Desktop中安装ubuntu
  • 【基于SprintBoot+Mybatis+Mysql】电脑商城项目之修改密码和个人资料
  • 6种MySQL高可用方案对比分析
  • 自学Java-面向对象编程入门
  • 在游戏本(6G显存)上本地部署Deepseek,运行一个14B大语言模型,并使用API访问
  • 【JavaScript】《JavaScript高级程序设计 (第4版) 》笔记-Chapter3-语言基础
  • MyBatis核心配置文件详解:从层级关系到实战配置
  • Oh3.2项目升级到Oh5.0(鸿蒙Next)具体踩坑记录(一)
  • 如何打开vscode系统用户全局配置的settings.json
  • JS实现一个通用的循环填充数组的方法
  • React--》使用Toast UI Calendar实现可定制日历的技巧与实践
  • Vim跳转文件及文件行结束符EOL
  • A2DP/HFP音频蓝牙模块+玩具,开启儿童成长智能时代
  • 20250205确认荣品RK3566开发板在Android13下可以使用命令行reboot -p关机
  • java面试题-集合篇
  • 【C++】STL——list的使用与底层实现
  • 第二次连接k8s平台注意事项
  • 后端生成二维码
  • 单节锂电池外部供电自动切换的电路学习
  • Git 工作区、暂存区与本地仓库的关系详解
  • TCP | RFC793
  • Django基础篇(1)--介绍
  • IDEA 中集成 Maven,配置环境、创建以及导入项目
  • 如何规避反爬虫机制
  • springBoot开发步骤和知识点
  • 测试驱动开发(TDD)实践:从理论到实践