多个@WebsocketGatways,每个连接多次调用生命周期挂钩

时间:2019-07-05 09:54:25

标签: nestjs

我的项目中有多个@WebsocketGateways,其中一个实现了OnGatewayConnection生命周期挂钩。似乎每个网关都被调用一次生命周期挂钩,即使只有一个实现它们也是如此。这是默认行为,错误还是我做错了什么?

CommonGateway

@WebSocketGateway()
export class CommonGateway implements OnGatewayConnection, OnGatewayDisconnect {
  @WebSocketServer() server;
  users: number = 0;

  handleConnection() {
    this.users++;

    console.log('USER CONNECTED: ', this.users);
  }

  handleDisconnect() {
    this.users--;

    console.log('USER Disconnected: ', this.users);
  }
}

DatesGateway

import {
  WebSocketGateway,
  SubscribeMessage,
  WsResponse,
} from '@nestjs/websockets';
import { CommonService } from 'src/common/common.service';

@WebSocketGateway()
export class DatesGateway {
  constructor(private readonly commonService: CommonService) {}

  @SubscribeMessage('dates-now')
  onNow(client): Promise<WsResponse<Date>> {
    return Promise.resolve(this.commonService.now).then(now => ({
      event: 'dates-now',
      data: now,
    }));
  }
}

控制台屏幕截图

enter image description here

可以找到一个演示该问题的小仓库here

谢谢

3 个答案:

答案 0 :(得分:1)

我在创建多个网关后才遇到此问题。我正在使用@nestjs/platform-ws@nestjs/websockets 6.10.1 版本。

使用以下解决方案,将创建一个WebSocket服务器,并且handleConnection将被调用一次(根据需要)。 handleDisconnect事件始终(正确)触发一次。重要的是要注意:

  1. 定义网关时必须包括名称空间。
    • 使用platform-ws适配器时,名称空间可以是唯一的或相同的。
    • 使用platform-socket.io适配器时,名称空间必须相同。
  2. 定义网关时必须包括端口。端口应与HTTP服务器端口相同,但应与不同,以免出现EADDRINUSEUnhandledPromiseRejectionWarning: Error: The HTTP/S server is already being used by another WebSocket server错误。
  3. 如果您创建许多网关,则可能会看到MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 close listeners added. Use emitter.setMaxListeners() to increase limit警告。我仍然需要研究这个。

app.gateway.ts

@WebSocketGateway(8080, {namespace: 'foo'})
export class AppGateway implements OnGatewayConnection, OnGatewayDisconnect {
  constructor() {}

  public handleConnection(): void {}

  public handleDisconnect(): void {}

  @SubscribeMessage('app:event')
  public handleGet(): WsResponse<string> {
    return {
      event: 'app:event',
      data: 'foobar'
    };
  }
}

user.gateway.ts

@WebSocketGateway(8080, {namespace: 'foo'})
export class UserGateway {
  constructor() {}

  @SubscribeMessage('user:event')
  public handleGet(): WsResponse<string> {
    return {
      event: 'user:event',
      data: 'foobar'
    };
  }
}

main.ts

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { WsAdapter } from '@nestjs/platform-ws';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.useWebSocketAdapter(new WsAdapter(app));
  await app.listen(80);
}
bootstrap();

欢迎对此有更多见识。

答案 1 :(得分:0)

这是因为您已在模块中多次声明了网关,而不是在主模块中将其声明为导出并在另一个模块中将其导入。我也遇到类似的问题,发现删除导出模块或将模块设置为全局装饰器模块都有帮助。在继续使用该模块之前,请研究该模块的全局装饰器:https://docs.nestjs.com/modules

答案 2 :(得分:0)

我找到了解决方案。 显然,这是NestJS中的错误(?),如果您根本不定义任何名称空间,则会为所有网关启动多个名称空间。然后是每个连接事件。

解决方案是在每个WebSocketGateways

上定义相同的名称空间
@WebSocketGateway({namespace: 'yournamespace'})

并像这样连接到客户端中的服务器:

io.connect('http://localhost:4200/yournamespace');