🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
## 适配器 `WebSockets` 模块与平台无关,因此,您可以通过使用 `WebSocketAdapter` 接口来创建自己的库(甚至是原生实现)。此接口强制使用下表中描述的几种方法: | | | | :------------------- | :------------------------------- | | `create` |将套接字实例连接到指定的端口 | | `bindClientConnect`| 绑定客户端连接事件 | | `bindClientDisconnect` | 绑定客户端断开连接事件(可选)| | `bindMessageHandlers`|将传入的消息绑定到适当的消息处理程序| | `close` | 终止服务器实例 | ### 拓展 socket.io [socket.io](https://github.com/socketio/socket.io) 包封装在一个 `IoAdapter` 类中。如果您想增强适配器的基本功能,该怎么办?例如,您的技术要求需要能够跨 `Web` 服务的多个负载平衡实例广播事件。为此,您可以扩展 `IoAdapter` 和覆盖单个方法,该方法的任务是实例化新的 `socket.io` 服务器。但首先,让我们安装所需的包。 >警告 要将 socket.io 与多个负载平衡实例一起使用,您要么必须通过在客户端 socket.io 配置中设置传输:['websocket'] 来禁用轮询,要么必须在负载平衡器中启用基于 cookie 的路由。 仅 Redis 是不够的。 浏览[此处](https://socket.io/docs/v4/using-multiple-nodes/#enabling-sticky-session)获取更多信息。 ```bash $ npm i --save socket.io-redis ``` 安装包后,我们可以创建一个 `RedisIoAdapter` 类。 ~~~typescript 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` 适配器。 ~~~typescript const app = await NestFactory.create(AppModule); const redisIoAdapter = new RedisIoAdapter(app); await redisIoAdapter.connectToRedis(); app.useWebSocketAdapter(redisIoAdapter); ~~~ ### ws 库 另一个可用的适配器 `WsAdapter` 反过来充当框架之间的代理,并集成了快速且经过全面测试的 `ws` 库。此适配器与原生浏览器 `WebSockets` 完全兼容,并且比 `socket.io` 包快得多。不幸的是,它具有明显更少的开箱即用功能。在某些情况下,您可能不一定需要它们。 为了使用 `ws`,我们首先必须安装所需的包: ```bash $ npm i --save @nestjs/platform-ws ``` 安装包后,我们可以切换适配器: ```typescript const app = await NestFactory.create(ApplicationModule); app.useWebSocketAdapter(new WsAdapter(app)); ``` > `WsAdapter` 是从 `@nestjs/platform-ws` 导入的。 ### 高级(自定义适配器) 出于演示目的,我们将手动集成 `ws` 库。如前所述,这个库的适配器已经创建,并从 `@nestjs/platform-ws` 包中作为 `WsAdapter` 类公开。下面是简化后的实现可能的样子: >ws-adapter.ts ```typescript 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 readonly app: INestApplicationContext) {} create(port: number, options: any = {}): any { return new ws.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 ```typescript const app = await NestFactory.create(ApplicationModule); app.useWebSocketAdapter(new WsAdapter(app)); ``` ### 示例 [这里](https://github.com/nestjs/nest/tree/master/sample/16-gateways-ws)提供了一个使用 `WsAdapter` 的工作示例。