【问题标题】:How to access websocket from controller or another component/services?如何从控制器或其他组件/服务访问 websocket?
【发布时间】:2019-06-12 05:17:47
【问题描述】:

我有一个 REST API,我想通过 websocket 向客户端发送事件。 如何在控制器或其他组件中注入 websocket 实例?

【问题讨论】:

    标签: socket.io nestjs nestjs-gateways


    【解决方案1】:

    class Gateway 可以注入另一个组件,并使用服务器实例。

    @Controller()
    export class AppController {
      constructor(
        private readonly appService: AppService,
        private readonly messageGateway: MessageGateway
      ) {}
    
      @Get()
      async getHello() {
        this.messageGateway.server.emit('messages', 'Hello from REST API');
        return this.appService.getHello();
      }
    }
    

    【讨论】:

    【解决方案2】:

    更好的解决方案是创建全局模块。然后,您可以从任何其他模块/控制器发出事件。 A. 如果您尝试在其他模块中使用 Afir 方法,它将创建多个 Gateway 实例。

    注意:这只是最简单的解决方案

    创建socket.module.ts

    import { Module, Global } from '@nestjs/common';
    import { SocketService } from './socket.service';
    
    @Global()
    @Module({
     controllers: [],
     providers: [SocketService],
     exports: [SocketService],
    })
    export class SocketModule {}
    

    socket.service.ts

    import { Injectable } from '@nestjs/common';
    import { Server } from 'socket.io';
    
    @Injectable()
    export class SocketService {
    
     public socket: Server = null;
    
    }
    

    app.gateway.tsafterInit函数

    import { WebSocketGateway, OnGatewayInit, OnGatewayConnection, OnGatewayDisconnect, WebSocketServer } from '@nestjs/websockets';
    import { Logger } from '@nestjs/common';
    import { Server, Socket } from 'socket.io';
    import { SocketService } from './socket/socket.service';
    
    @WebSocketGateway()
    export class AppGateway implements OnGatewayInit, OnGatewayConnection, OnGatewayDisconnect {
    
      constructor(private socketService: SocketService){
    
      }
      @WebSocketServer() public server: Server;
      private logger: Logger = new Logger('AppGateway');
    
    
      afterInit(server: Server) {
        this.socketService.socket = server;
      }
    
      handleDisconnect(client: Socket) {
        this.logger.log(`Client disconnected: ${client.id}`);
      }
    
      handleConnection(client: Socket, ...args: any[]) {
        this.logger.log(`Client connected: ${client.id}`);
      }
    
    }
    

    然后将SocketModule导入AppModule,就可以在任何地方使用Socket service了。

    【讨论】:

    • (我认为这应该是公认的答案) - 谢谢,它真的帮助了我。在这样做之前,每个新的客户端连接都被记录了不止一次,这可能是由于在每个模块导入中创建了多个实例。
    • 也为我工作,谢谢
    【解决方案3】:

    我想@Raold 错过了documentation 中的一个事实:

    网关不应使用请求范围的提供程序,因为它们必须充当单例。每个网关都封装了一个真实的socket,不能多次实例化。

    这意味着我们既不能多次实例化网关类,也不能显式地使用注入作用域特性。

    因此,只为一个命名空间创建一个网关是正确的,它只会生成一个 websocket 或 socket.io 服务器实例。

    【讨论】:

    • 感谢您的反馈。我为有效的特定案例提供了更好的解决方案。我不认为这句话与我的例子直接相关。如果你能解释为什么这从根本上是错误的并提供一些例子会更好。
    猜你喜欢
    • 1970-01-01
    • 2012-01-30
    • 2019-03-28
    • 2014-10-23
    • 2015-09-14
    • 2012-03-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多