WebSocket 连接前后端实现

WebSocket 连接前后端实现(详细示例)

WebSocket 适用于 实时通信 场景,如即时聊天在线状态通知推送 等。下面是完整的 前后端 WebSocket 连接示例 ,包括 Node.js(Egg.js / NestJS)后端React / Vue 前端


🔵 1. 后端(Node.js)WebSocket 实现

后端可以使用 WebSocket Server 处理连接、消息收发、断线重连等逻辑。这里提供 Egg.js 和 NestJS 两种方案

方案 1:Egg.js WebSocket

Egg.js 官方提供了 @eggjs/plugin-websocket 插件,适用于 WebSocket 连接管理。

(1)安装 WebSocket 插件

lua 复制代码
npm install egg-socket.io --save

(2)配置 WebSocket

编辑 config/plugin.ts,启用 socket.io

arduino 复制代码
export default {
  io: {
    enable: true,
    package: 'egg-socket.io',
  },
};

编辑 config/config.default.ts

arduino 复制代码
export default {
  io: {
    namespace: {
      '/chat': {
        connectionMiddleware: ['auth'], // 可选:认证中间件
        packetMiddleware: ['filter'],  // 可选:数据过滤
      },
    },
  },
};

(3)实现 WebSocket 逻辑

新建 app/io/controller/chat.ts

javascript 复制代码
import { Controller } from 'egg';

export default class ChatController extends Controller {
  async connect() {
    const { ctx, app } = this;
    const socket = ctx.socket;
    const { id } = socket; // 获取 socket ID

    console.log(`🔗 用户已连接: ${id}`);

    // 监听消息
    socket.on('message', async (data) => {
      console.log(`📩 收到消息: ${data}`);
      // 发送给所有连接的客户端
      app.io.of('/chat').emit('message', data);
    });

    // 监听断开
    socket.on('disconnect', () => {
      console.log(`❌ 用户断开连接: ${id}`);
    });
  }
}

(4)注册 WebSocket 事件

app/io/middleware/auth.ts 添加身份验证:

javascript 复制代码
export default async (ctx, next) => {
  const { socket } = ctx;
  const token = socket.handshake.query.token; // 获取前端传递的 token
  console.log(`🔑 认证 Token: ${token}`);

  if (!token || token !== 'VALID_TOKEN') {
    return socket.disconnect(); // 认证失败,断开连接
  }

  await next();
};

方案 2:NestJS WebSocket

NestJS 提供了 @nestjs/websockets 处理 WebSocket 连接。

(1)安装 WebSocket 依赖

bash 复制代码
npm install @nestjs/websockets @nestjs/platform-socket.io

(2)创建 WebSocket 网关

新建 chat.gateway.ts

typescript 复制代码
import { WebSocketGateway, SubscribeMessage, MessageBody, OnGatewayConnection, OnGatewayDisconnect, WebSocketServer } from '@nestjs/websockets';
import { Server, Socket } from 'socket.io';

@WebSocketGateway({ namespace: '/chat', cors: true }) // 开启跨域
export class ChatGateway implements OnGatewayConnection, OnGatewayDisconnect {
  
  @WebSocketServer() server: Server;

  handleConnection(client: Socket) {
    console.log(`🔗 用户连接: ${client.id}`);
  }

  handleDisconnect(client: Socket) {
    console.log(`❌ 用户断开: ${client.id}`);
  }

  @SubscribeMessage('message')
  handleMessage(@MessageBody() message: string): void {
    console.log(`📩 收到消息: ${message}`);
    this.server.emit('message', message); // 广播消息
  }
}

(3)注册 WebSocket

app.module.ts 中注册 ChatGateway

python 复制代码
import { Module } from '@nestjs/common';
import { ChatGateway } from './chat.gateway';

@Module({
  providers: [ChatGateway],
})
export class AppModule {}

🟡 2. 前端 WebSocket 连接

前端可以使用 socket.io-client 或原生 WebSocket 进行通信。

方案 1:React WebSocket(使用 socket.io-client)

(1)安装 socket.io-client

lua 复制代码
npm install socket.io-client

(2)创建 WebSocket 连接

新建 useWebSocket.ts Hook:

javascript 复制代码
import { useEffect, useState } from 'react';
import { io } from 'socket.io-client';

const SOCKET_URL = 'http://localhost:7001/chat';

export default function useWebSocket() {
  const [socket, setSocket] = useState(null);
  const [messages, setMessages] = useState<string[]>([]);

  useEffect(() => {
    const newSocket = io(SOCKET_URL, {
      query: { token: 'VALID_TOKEN' }, // 认证 Token
    });

    newSocket.on('connect', () => console.log('✅ 已连接 WebSocket'));
    newSocket.on('message', (msg) => {
      console.log('📩 收到消息:', msg);
      setMessages((prev) => [...prev, msg]);
    });

    setSocket(newSocket);

    return () => newSocket.close(); // 组件卸载时断开连接
  }, []);

  return { socket, messages };
}

(3)在 React 组件中使用

javascript 复制代码
import useWebSocket from './useWebSocket';

export default function Chat() {
  const { socket, messages } = useWebSocket();
  const [input, setInput] = useState('');

  const sendMessage = () => {
    if (socket && input) {
      socket.emit('message', input);
      setInput('');
    }
  };

  return (
    <div>
      <h1>💬 聊天</h1>
      <ul>
        {messages.map((msg, i) => (
          <li key={i}>{msg}</li>
        ))}
      </ul>
      <input value={input} onChange={(e) => setInput(e.target.value)} />
      <button onClick={sendMessage}>发送</button>
    </div>
  );
}

方案 2:Vue WebSocket(使用 socket.io-client)

(1)安装 socket.io-client

lua 复制代码
npm install socket.io-client

(2)创建 WebSocket 连接

新建 useWebSocket.js

javascript 复制代码
import { ref, onMounted, onUnmounted } from 'vue';
import { io } from 'socket.io-client';

const SOCKET_URL = 'http://localhost:7001/chat';

export default function useWebSocket() {
  const messages = ref([]);
  let socket;

  onMounted(() => {
    socket = io(SOCKET_URL, { query: { token: 'VALID_TOKEN' } });

    socket.on('message', (msg) => {
      console.log('📩 收到消息:', msg);
      messages.value.push(msg);
    });
  });

  const sendMessage = (msg) => {
    if (socket) socket.emit('message', msg);
  };

  onUnmounted(() => {
    if (socket) socket.close();
  });

  return { messages, sendMessage };
}

(3)在 Vue 组件中使用

xml 复制代码
<template>
  <div>
    <h1>💬 聊天</h1>
    <ul>
      <li v-for="(msg, i) in messages" :key="i">{{ msg }}</li>
    </ul>
    <input v-model="input" />
    <button @click="sendMessage(input)">发送</button>
  </div>
</template>

<script setup>
import { ref } from 'vue';
import useWebSocket from './useWebSocket';

const { messages, sendMessage } = useWebSocket();
const input = ref('');
</script>

总结

🔹 Egg.js / NestJS 实现 WebSocket 后端

🔹 React / Vue 实现 WebSocket 前端连接

🔹 socket.io 方便管理 WebSocket 连接

🔹 支持认证 / 断线重连 / 消息持久化

相关推荐
爱生活的苏苏10 分钟前
vue生成二维码图片+文字说明
前端·vue.js
拉不动的猪13 分钟前
安卓和ios小程序开发中的兼容性问题举例
前端·javascript·面试
炫彩@之星18 分钟前
Chrome书签的导出与导入:步骤图
前端·chrome
贩卖纯净水.29 分钟前
浏览器兼容-polyfill-本地服务-优化
开发语言·前端·javascript
前端百草阁35 分钟前
从npm库 Vue 组件到独立SDK:打包与 CDN 引入的最佳实践
前端·vue.js·npm
夏日米米茶36 分钟前
Windows系统下npm报错node-gyp configure got “gyp ERR“解决方法
前端·windows·npm
且白1 小时前
vsCode使用本地低版本node启动配置文件
前端·vue.js·vscode·编辑器
程序研1 小时前
一、ES6-let声明变量【解刨分析最详细】
前端·javascript·es6
siwangqishiq22 小时前
Vulkan Tutorial 教程翻译(四) 绘制三角形 2.2 呈现
前端
李三岁_foucsli2 小时前
js中消息队列和事件循环到底是怎么个事,宏任务和微任务还存在吗?
前端·chrome