跳转至

适配器

WebSockets 模块是平台无关的,因此,你可以通过使用WebSocketAdapter接口带来自己的库(甚至是本地实现)。 该接口强制实现以下表中描述的几种方法:

create 基于传递的参数创建套接字实例
bindClientConnect 绑定客户端连接事件
bindClientDisconnect 绑定客户端断开事件(可选*)
bindMessageHandlers 将传入消息绑定到相应的消息处理程序
close 终止服务器实例

扩展 socket.io

socket.io包被包装在一个 IoAdapter 类中。 如果您想增强适配器的基本功能,该怎么办呢? 例如,您的技术需求要求能够跨 web 服务的多个负载平衡实例广播事件。 为此,你可以扩展IoAdapter并覆盖单个方法,该方法负责实例化新的socket.io服务器。 但首先,让我们安装所需的包。

$ npm i --save socket.io-redis

一旦安装了包,我们就可以创建一个 RedisIoAdapter 类。

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

const pubClient = new RedisClient({ host: 'localhost', port: 6379 });
const subClient = pubClient.duplicate();
const redisAdapter = createAdapter({ pubClient, subClient });

export class RedisIoAdapter extends IoAdapter {
  createIOServer(port: number, options?: ServerOptions): any {
    const server = super.createIOServer(port, options);
    server.adapter(redisAdapter);
    return server;
  }
}

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

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

Ws 库

另一个可用的适配器是“WsAdapter”,它充当框架之间的代理,集成了快速且经过彻底测试的ws库。 这个适配器与本地浏览器 WebSockets 完全兼容,而且比 socket.io 包快得多。 不幸的是,它的可用功能少得多。 在某些情况下,您可能并不需要它们。

Hint

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导入的。

高级(自定义适配器)

出于演示目的,我们将手动集成ws库。 正如前面提到的,这个库的适配器已经创建,并作为一个WsAdapter类从@nestjs/platform-ws包中公开。 下面是简化后的实现可能看起来的样子:

ws-adapter
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 的工作示例此处.