如何从控制器或其他组件/服务访问 websocket?

Posted

技术标签:

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

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

【问题讨论】:

【参考方案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();
  

【讨论】:

欢迎来到 ***! :-) 不要在答案文本中写 [已解决],而是考虑接受您的答案。您可以在 48 小时后这样做。见***.com/help/accepted-answer【参考方案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 服务器实例。

【讨论】:

感谢您的反馈。我为有效的特定案例提供了更好的解决方案。我不认为这句话与我的例子直接相关。如果你能解释为什么这从根本上是错误的并提供一些例子会更好。

以上是关于如何从控制器或其他组件/服务访问 websocket?的主要内容,如果未能解决你的问题,请参考以下文章

服务层和数据访问对象层如何适应 Spring MVC 架构?

如何将状态值从一个组件访问到位于单独文件中的其他功能(不是组件)?反应js

如何访问 html5 本地存储 asp.net mvc 3 控制器/管道

CakePHP 2.0:从模型或其控制器访问未关联的模型?

Vue3 从控制台访问组件数据属性

IPHONE 如何从其他类/视图控制器访问变量