## 適配器
`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` 的工作示例。
- 介紹
- 概述
- 第一步
- 控制器
- 提供者
- 模塊
- 中間件
- 異常過濾器
- 管道
- 守衛
- 攔截器
- 自定義裝飾器
- 基礎知識
- 自定義提供者
- 異步提供者
- 動態模塊
- 注入作用域
- 循環依賴
- 模塊參考
- 懶加載模塊
- 應用上下文
- 生命周期事件
- 跨平臺
- 測試
- 技術
- 數據庫
- Mongo
- 配置
- 驗證
- 緩存
- 序列化
- 版本控制
- 定時任務
- 隊列
- 日志
- Cookies
- 事件
- 壓縮
- 文件上傳
- 流式處理文件
- HTTP模塊
- Session(會話)
- MVC
- 性能(Fastify)
- 服務器端事件發送
- 安全
- 認證(Authentication)
- 授權(Authorization)
- 加密和散列
- Helmet
- CORS(跨域請求)
- CSRF保護
- 限速
- GraphQL
- 快速開始
- 解析器(resolvers)
- 變更(Mutations)
- 訂閱(Subscriptions)
- 標量(Scalars)
- 指令(directives)
- 接口(Interfaces)
- 聯合類型
- 枚舉(Enums)
- 字段中間件
- 映射類型
- 插件
- 復雜性
- 擴展
- CLI插件
- 生成SDL
- 其他功能
- 聯合服務
- 遷移指南
- Websocket
- 網關
- 異常過濾器
- 管道
- 守衛
- 攔截器
- 適配器
- 微服務
- 概述
- Redis
- MQTT
- NATS
- RabbitMQ
- Kafka
- gRPC
- 自定義傳輸器
- 異常過濾器
- 管道
- 守衛
- 攔截器
- 獨立應用
- Cli
- 概述
- 工作空間
- 庫
- 用法
- 腳本
- Openapi
- 介紹
- 類型和參數
- 操作
- 安全
- 映射類型
- 裝飾器
- CLI插件
- 其他特性
- 遷移指南
- 秘籍
- CRUD 生成器
- 熱重載
- MikroORM
- TypeORM
- Mongoose
- 序列化
- 路由模塊
- Swagger
- 健康檢查
- CQRS
- 文檔
- Prisma
- 靜態服務
- Nest Commander
- 問答
- Serverless
- HTTP 適配器
- 全局路由前綴
- 混合應用
- HTTPS 和多服務器
- 請求生命周期
- 常見錯誤
- 實例
- 遷移指南
- 發現
- 誰在使用Nest?