logologo
文档仓库
文档仓库
logologo
开始

概述

第一步
控制器
提供者
模块
中间件
异常过滤器
管道
守卫
拦截器
自定义装饰器

基础

自定义提供程序
异步提供者
动态模块
注入作用域
循环依赖
模块引用
懒加载模块
执行上下文
生命周期事件
发现服务
平台无关
单元测试

技术

配置
SQL
Mongo
验证
缓存
序列化
版本控制
任务调度
队列
日志
Cookies
事件
压缩
文件上传
文件流
HTTP 模块
Session
MVC
性能(Fastify)
SSE

安全

认证
授权
加密与哈希
Helmet
CORS
CSRF
速率限制

GraphQL

快速开始
解析器
变更
订阅
标量
指令
接口
联合与枚举
字段中间件
类型映射
插件
复杂度
扩展
CLI 插件
生成SDL
共享模型
其他功能
联邦

WebSocket

网关
异常过滤器
管道
守卫
拦截器
适配器

微服务

基础
Redis
MQTT
NATS
RabbitMQ
Kafka
gRPC
自定义传输
异常过滤器
管道
守卫
拦截器
部署
独立应用程序

CLI

概述
工作区
库
用法
脚本

OpenAPI

介绍
装饰器
类型映射
操作
其他特性
安全
类型与参数
CLI 插件

实用示例

REPL
CRUD生成器
SWC
Passport(认证)
热重载
MikroORM
TypeORM
Mongoose
Sequelize
路由模块
Swagger
健康检查
CQRS
Compodoc
Prisma
Sentry
静态资源
Commander
异步本地存储
Necord
套件(原Automock)

常见问题

Serverless
HTTP 适配器
长连接
全局前缀
原始请求体
混合应用
HTTPS & 多服务器
请求生命周期
错误

开发工具

概述
CI/CD
迁移指南
API参考(官方)

生态与案例

谁在用
精彩资源

支持

支持

社区

贡献者

最后更新于: 2025/11/18 02:11:37

上一页拦截器
下一页基础

#适配器

WebSockets 模块是平台无关的,因此你可以通过使用 WebSocketAdapter 接口来引入自己的库(甚至是原生实现)。该接口强制要求实现下表中描述的少数几个方法:

方法描述
create根据传入的参数创建套接字实例
bindClientConnect绑定客户端连接事件
bindClientDisconnect绑定客户端断开连接事件(可选*)
bindMessageHandlers将传入消息绑定到对应的消息处理器
close终止服务器实例

#扩展 socket.io

socket.io 包被封装在 IoAdapter 类中。如果您想增强适配器的基础功能该怎么办?例如,您的技术要求需要具备跨多个负载均衡的 Web 服务实例广播事件的能力。为此,您可以扩展 IoAdapter 并重写一个负责实例化新 socket.io 服务器的方法。但首先,我们需要安装所需的包。

警告

要在多个负载均衡实例中使用 socket.io,您要么必须在客户端 socket.io 配置中通过设置 transports: ['websocket'] 来禁用轮询,要么必须在负载均衡器中启用基于 cookie 的路由。仅 Redis 是不够的。更多信息请参阅此处 。

$ npm i --save redis socket.io @socket.io/redis-adapter

安装完该包后,我们就可以创建 RedisIoAdapter 类了。

import { IoAdapter } from '@nestjs/platform-socket.io';
import { ServerOptions } from 'socket.io';
import { createAdapter } from '@socket.io/redis-adapter';
import { createClient } from 'redis';

export class RedisIoAdapter extends IoAdapter {
  private adapterConstructor: ReturnType<typeof createAdapter>;

  async connectToRedis(): Promise<void> {
    const pubClient = createClient({ url: `redis://localhost:6379` });
    const subClient = pubClient.duplicate();

    await Promise.all([pubClient.connect(), subClient.connect()]);

    this.adapterConstructor = createAdapter(pubClient, subClient);
  }

  createIOServer(port: number, options?: ServerOptions): any {
    const server = super.createIOServer(port, options);
    server.adapter(this.adapterConstructor);
    return server;
  }
}

之后,只需切换到新创建的 Redis 适配器即可。

const app = await NestFactory.create(AppModule);
const redisIoAdapter = new RedisIoAdapter(app);
await redisIoAdapter.connectToRedis();

app.useWebSocketAdapter(redisIoAdapter);

#Ws 库

另一个可用的适配器是 WsAdapter,它充当框架与集成的极速且经过全面测试的 ws 库之间的代理。该适配器完全兼容原生浏览器 WebSocket,且比 socket.io 包快得多。遗憾的是,它开箱即用的功能要少得多。不过在有些情况下,您可能并不需要这些功能。

注意

ws 库不支持命名空间(由 socket.io 推广的通信通道)。但为了模拟这一特性,您可以在不同路径上挂载多个 ws 服务器(示例: @WebSocketGateway({ path: '/users' }) )。

要使用 ws,我们首先需要安装这个必需的包:

$ npm i --save @nestjs/platform-ws

安装该包后,我们可以切换适配器:

const app = await NestFactory.create(AppModule);
app.useWebSocketAdapter(new WsAdapter(app));
提示

WsAdapter 是从 @nestjs/platform-ws 导入的。

wsAdapter 设计用于处理 { event: string, data: any } 格式的消息。如果需要接收和处理其他格式的消息,需配置消息解析器将其转换为所需格式。

const wsAdapter = new WsAdapter(app, {
  // 处理 [event, data] 格式的消息
  messageParser: (data) => {
    const [event, payload] = JSON.parse(data.toString());
    return { event, data: payload };
  },
});

或者,您也可以在创建适配器后通过 setMessageParser 方法配置消息解析器:

const wsAdapter = new WsAdapter(app);
wsAdapter.setMessageParser((data) => {
  const parsed = JSON.parse(data.toString());
  return { event: parsed.type, data: parsed.payload };
});
app.useWebSocketAdapter(wsAdapter);

#ws 库的优势

使用 ws 库相比 socket.io 有以下优势:

  • 性能更高:ws 是原生 WebSocket 实现,性能更佳
  • 更轻量:包体积更小,依赖更少
  • 浏览器兼容:与浏览器原生 WebSocket API 完全兼容
  • 更低延迟:减少了额外的协议开销

但也有一些限制:

  • 功能较少:缺少自动重连、房间等高级功能
  • 无命名空间:不支持 socket.io 的命名空间特性(可通过不同路径挂载多个服务器来模拟)
// 在不同路径挂载多个 WebSocket 服务器来模拟命名空间
@WebSocketGateway({ path: '/chat' })
export class ChatGateway {}

@WebSocketGateway({ path: '/notifications' })
export class NotificationsGateway {}

#高级选项(自定义适配器)

出于演示目的,我们将手动集成 ws 库。如前所述,该库的适配器已经创建并通过 @nestjs/platform-ws 包的 WsAdapter 类公开。以下是简化后的实现可能呈现的样子:

ws-adapter.ts
import * as WebSocket from 'ws';
import { WebSocketAdapter, INestApplicationContext } from '@nestjs/common';
import { MessageMappingProperties } from '@nestjs/websockets';
import { Observable, fromEvent, EMPTY } from 'rxjs';
import { mergeMap, filter } from 'rxjs/operators';

export class WsAdapter implements WebSocketAdapter {
 constructor(private app: INestApplicationContext) {}

 create(port: number, options: any = {}): any {
   return new WebSocket.Server({ port, ...options });
 }

 bindClientConnect(server, callback: Function) {
   server.on('connection', callback);
 }

 bindMessageHandlers(
   client: WebSocket,
   handlers: MessageMappingProperties[],
   process: (data: any) => Observable<any>,
 ) {
   fromEvent(client, 'message')
     .pipe(
       mergeMap(data => this.bindMessageHandler(data, handlers, process)),
       filter(result => result),
     )
     .subscribe(response => client.send(JSON.stringify(response)));
 }

 bindMessageHandler(
   buffer,
   handlers: MessageMappingProperties[],
   process: (data: any) => Observable<any>,
 ): Observable<any> {
   const message = JSON.parse(buffer.data);
   const messageHandler = handlers.find(
     handler => handler.message === message.event,
   );
   if (!messageHandler) {
     return EMPTY;
   }
   return process(messageHandler.callback(message.data));
 }

 close(server) {
   server.close();
 }
}
注意

当你需要使用 ws 库时,请使用内置的 WsAdapter 而不是自己创建。

接着,我们可以通过 useWebSocketAdapter() 方法设置自定义适配器:

main.ts
const app = await NestFactory.create(AppModule);
app.useWebSocketAdapter(new WsAdapter(app));

#示例

一个使用 WsAdapter 的工作示例可在此处查看。