如何从控制器或另一个组件/服务访问WebSocket?

10

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

3个回答

38

更好的解决方案是创建全局模块。这样,您可以从任何其他模块/控制器中发出事件。如果您尝试在其他模块中使用它,则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.ts文件的afterInit函数。

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}`);
  }

}

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


1
谢谢,这真的帮了我很多。在这之前,每个新连接的客户端都被记录了多次,可能是由于每个模块导入时创建了多个实例。 - Guilherme Abacherli
也对我有用,谢谢。 - IMalaniak

31

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();
  }
}

1
欢迎来到Stackoverflow!:-) 在您的答案文本中,不要写[solved],请考虑接受您的答案。您可以在48小时后这样做。请参阅https://stackoverflow.com/help/accepted-answer - Kim Kern
如果您想使用此方法向特定的客户端发送事件,该如何操作? - NicoleZ

1

我想@Raold在文档中错过了一个事实:

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

这意味着我们既不能多次实例化网关类,也不能使用注入范围功能显式地进行实例化。

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


6
谢谢反馈。我提供了一个适用的特定案例更好的解决方案。我认为这个引语与我的例子没有直接关联。如果您能解释一下为什么这是根本错误的,并且提供一些例子,那将更好。 - Raold

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接