Nest.js 框架 WebSockets 与实时通信

person 无限可能    watch_later 2024-10-06 15:36:46
visibility 208    class WebSockets    bookmark 专栏

WebSockets 是一种网络通信协议,允许在客户端和服务器之间建立持久的连接,实现实时数据传输。Nest.js 提供了强大的支持来构建基于 WebSockets 的实时应用。本文将详细介绍如何在 Nest.js 中使用 WebSockets,包括如何创建实时应用,覆盖所有相关属性和方法。

1. WebSocket 模块概述

Nest.js 内置了对 WebSocket 的支持,通过 @nestjs/websockets 模块,可以轻松创建 WebSocket 服务器和客户端。它支持多种 WebSocket 库,例如 Socket.IO、ws 等。

2. 安装依赖

首先,我们需要安装 @nestjs/websocketssocket.io(如果使用 Socket.IO):

npm install @nestjs/websockets socket.io

3. 创建 WebSocket 模块

3.1 创建 WebSocket Gateway

在 Nest.js 中,WebSocket Gateway 是处理 WebSocket 事件的类。我们将创建一个简单的聊天应用示例。

创建一个 chat.gateway.ts 文件:

import {
  WebSocketGateway,
  WebSocketServer,
  SubscribeMessage,
  MessageBody,
  OnGatewayInit,
  OnGatewayConnection,
  OnGatewayDisconnect,
} from '@nestjs/websockets';
import { Server, Socket } from 'socket.io';

@WebSocketGateway({
  cors: {
    origin: '*', // 允许所有来源的请求
  },
})
export class ChatGateway
  implements OnGatewayInit, OnGatewayConnection, OnGatewayDisconnect
{
  @WebSocketServer()
  server: Server;

  afterInit(server: Server) {
    console.log('WebSocket server initialized');
  }

  handleConnection(client: Socket) {
    console.log(`Client connected: ${client.id}`);
  }

  handleDisconnect(client: Socket) {
    console.log(`Client disconnected: ${client.id}`);
  }

  @SubscribeMessage('message')
  handleMessage(@MessageBody() data: { sender: string; content: string }) {
    console.log('Received message:', data);
    this.server.emit('message', data); // 广播消息给所有连接的客户端
  }
}

在这个 Gateway 中,我们实现了以下功能:

  • onGatewayInit:在 WebSocket 服务器初始化后执行。
  • onGatewayConnection:处理客户端连接。
  • onGatewayDisconnect:处理客户端断开连接。
  • handleMessage:处理消息事件,并将接收到的消息广播给所有连接的客户端。

3.2 创建 Chat Module

接下来,我们需要创建一个聊天模块,以便将我们的 Gateway 注册到应用中。在 chat.module.ts 中:

import { Module } from '@nestjs/common';
import { ChatGateway } from './chat.gateway';

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

3.3 更新 App Module

将 ChatModule 添加到根模块 app.module.ts 中:

import { Module } from '@nestjs/common';
import { ChatModule } from './chat/chat.module';

@Module({
  imports: [ChatModule],
})
export class AppModule {}

4. 创建前端客户端

为了测试 WebSocket,我们需要创建一个简单的前端客户端。可以使用 HTML 和 JavaScript 来实现。

4.1 创建 HTML 页面

创建一个 index.html 文件:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>WebSocket Chat</title>
    <script src="/socket.io/socket.io.js"></script>
</head>
<body>
    <h1>WebSocket Chat</h1>
    <input id="username" placeholder="Enter your name" />
    <input id="message" placeholder="Enter a message" />
    <button id="sendBtn">Send</button>
    <ul id="messages"></ul>

    <script>
        const socket = io('http://localhost:3000');

        document.getElementById('sendBtn').onclick = () => {
            const username = document.getElementById('username').value;
            const message = document.getElementById('message').value;
            socket.emit('message', { sender: username, content: message });
            document.getElementById('message').value = ''; // 清空输入框
        };

        socket.on('message', (data) => {
            const li = document.createElement('li');
            li.textContent = `${data.sender}: ${data.content}`;
            document.getElementById('messages').appendChild(li);
        });
    </script>
</body>
</html>

在这个简单的前端页面中:

  • 我们创建了一个输入框用于输入用户名和消息。
  • 通过 Socket.IO 连接到 WebSocket 服务器。
  • 发送消息后,通过 socket.emit 发送到服务器,并通过 socket.on 监听消息事件,实时更新消息列表。

5. 运行应用

确保 WebSocket 服务器和前端都在运行:

  1. 启动 Nest.js 应用:

    npm run start
    
  2. 打开 index.html 文件(可以使用本地服务器如 http-server 来托管该文件),输入用户名和消息,点击发送。

  3. 在不同的浏览器窗口或标签页中打开 index.html 文件,测试实时消息传递。

6. 进阶功能

6.1 添加用户身份验证

在实际应用中,我们可能需要对用户进行身份验证,可以通过 JWT 或其他方式实现。示例中我们假设用户已通过某种方式登录并获取用户名。

6.2 处理房间

WebSocket 支持房间的概念,允许用户加入特定的房间以便更好地管理消息。

@SubscribeMessage('joinRoom')
handleJoinRoom(client: Socket, room: string) {
  client.join(room);
  console.log(`Client ${client.id} joined room: ${room}`);
}

@SubscribeMessage('message')
handleMessage(@MessageBody() data: { sender: string; content: string; room: string }) {
  this.server.to(data.room).emit('message', data); // 仅广播到特定房间
}

用户可以通过 joinRoom 事件加入特定房间,在发送消息时也可以指定房间,从而实现分组聊天。

7. 总结

通过上述步骤,我们成功实现了一个基于 Nest.js 的 WebSocket 实时聊天应用。我们创建了 WebSocket Gateway、模块,并实现了基本的消息处理和广播功能。结合简单的前端代码,我们可以实时发送和接收消息。

  • WebSocket Gateway:处理连接、消息和广播。
  • Socket.IO:简化了 WebSocket 的使用,使得事件驱动的编程变得简单。
  • 模块化设计:将聊天功能封装在一个独立的模块中,便于管理和扩展。

通过学习 WebSockets 和 Nest.js,我们能够为应用添加实时通信能力,这对于聊天应用、通知系统等场景非常重要。进一步的扩展可以包括用户身份验证、房间管理、消息历史记录等功能,以满足更复杂的需求。

评论区
评论列表
menu