【问题标题】:Socket.io acknowledgement in Nest.jsNest.js 中的 Socket.io 确认
【发布时间】:2018-09-11 18:02:44
【问题描述】:

我正在尝试在 Nest.js WebSocketGateways 中启用 socket.io 确认回调。

我希望能够发出这个:

socket.emit('event', 'some data', function (response) {
  //do something
})

并像这样使用消息处理程序:

@SubscribeMessage('event')
onStart(client, data, ack) {
  //Do stuff
  ack('stuff completed');
}

根据this nestjs/nest GitHub issue 问题,库中不支持它,因此您必须构建自己的 websocket 适配器。我试过了,但不知道该怎么做。我想我需要在bindMessageHandlers 函数中做一些特别的事情,但我的尝试都是徒劳的。 这是框架中捆绑的默认 socket.io 适配器中的bindMessageHandlers 实现:

public bindMessageHandlers(
  client,
  handlers: MessageMappingProperties[],
  process: (data: any) => Observable<any>,
) {
  handlers.forEach(({ message, callback }) =>
    Observable.fromEvent(client, message)
      .switchMap(data => process(callback(data)))
      .filter(result => !!result && result.event)
      .subscribe(({ event, data }) => client.emit(event, data)),
  );
}

有人对我将如何实现这一点有任何指示吗?

【问题讨论】:

    标签: javascript socket.io nestjs


    【解决方案1】:

    在对 NestJS 进行了短暂的研究之后。 这是我的解决方案。

    src
    ├── app.controller.spec.ts
    ├── app.controller.ts
    ├── app.module.ts
    ├── common
    │   └── adapters
    │       └── ws-adapter.ts
    ├── events
    │   ├── events.gateway.ts
    │   └── events.module.ts
    └── main.ts
    

    main.ts文件

    import { NestFactory } from '@nestjs/core';
    import { AppModule } from './app.module';
    import { WsAdapter } from './common/adapters/ws-adapter.ts';
    import * as cors from 'cors';
    
    let corsOptions = {
        origin: 'http://nestjs.test',
        credentials: true
    }
    
    async function bootstrap() {
        const app = await NestFactory.create(AppModule);
        app.useWebSocketAdapter(new WsAdapter(3000));
        app.use(cors(corsOptions));
        await app.listen(4000);
    }
    bootstrap();
    

    因为当我们使用 WebSocket Adapter 时,我们不能再使用与 NestJS 应用程序相同的端口了。

    common\adapters\ws-adapter.ts文件

    import * as WebSocket from 'ws';
    import { WebSocketAdapter } from '@nestjs/common';
    import { IoAdapter } from '@nestjs/websockets';
    import { MessageMappingProperties } from '@nestjs/websockets';
    import { Observable } from 'rxjs/Observable';
    import 'rxjs/add/observable/fromEvent';
    import 'rxjs/add/observable/empty';
    import 'rxjs/add/operator/switchMap';
    import 'rxjs/add/operator/filter';
    
    export class WsAdapter extends IoAdapter {
      public bindMessageHandlers(
        client,
        handlers: MessageMappingProperties[],
        process: (data: any) => Observable<any>,
      ) {
        handlers.forEach(({ message, callback }) => {
            client.on('event', function (data, ack) {
                console.log('DATA', data)
                ack('woot')
            })
            Observable.fromEvent(client, message)
                .switchMap(data => process(callback(data)))
                .filter(result => !!result && result.event)
                .subscribe(({ event, data }) => client.emit(event, data))
            });
      }
    }
    

    我的客户端源代码

    socket.emit('event', {data: 'some data'}, function (response) {
        console.log('RESPONSE', response)
    });
    socket.on('event', function(data) {
        console.log('ON EVENT', data);
    });
    

    这是我的结果

    希望对您有所帮助!

    【讨论】:

    • 您的解决方案实际上不起作用,因为我想从网关中的修饰函数运行确认函数。在您的示例中,我必须对适配器中的每个套接字事件进行硬编码,即使这样也行不通,因为我无法访问网关中的服务等。
    【解决方案2】:

    更新:Nest 5.0 中添加了对确认的支持。
    如果套接字提供程序将多个参数传递给SubscribeMessage 处理程序,则request 参数将是一个包含这些参数的数组。

    例如使用默认的socket.io-adapter:

    @SubscribeMessage('event')
    async onEvent(client, request) {
      let data = request[0]
      let ack = request[1] //the acknowledgement function
    }
    

    一个问题是,如果您不提供确认函数request 将不是一个数组,而只是data 对象。

    在我当前的一个项目中,我通过创建一个提取数据和确认函数的辅助函数来解决这个问题,或者创建一个占位符,这意味着我可以随时调用 ack 函数而不考虑它的存在:

    export function extractRequest (req: any): { data: any, ack?: Function } {
      if (Array.isArray(req)) {
        const [data, ack] = req
        return { data, ack }
      } else {
        return { data: req, ack: () => {} }
      }
    }
    

    旧答案: 目前的情况是,如果不修改 Nest 源,这是不可能的。它将在即将发布的 5.0 版本中添加。当它发布时,我会用一个例子来更新这个答案。

    来源:https://github.com/nestjs/nest/issues/581

    【讨论】:

      【解决方案3】:

      只需使用来自 SubscribeMessage 的 return 语句

      // server
      @SubscribeMessage('message')
        async onMessage(
          client: Socket, query: string
        ) {
          try {
            console.log(query) 
            return 'hello'
          } catch (e) {
            // ...
          } 
        }
      

      在客户端使用函数作为第三个参数

      // client
      this.socket.emit('message', query, (res) => {
        console.log(res); // should log 'hello'
      });
      

      【讨论】:

        【解决方案4】:

        你可以试试这个模块:https://www.npmjs.com/package/nestjs-socket-handlers-with-ack。它在后台调用确认函数,您只需要返回一些值或抛出错误。希望对你有帮助

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-10-19
          • 1970-01-01
          • 2019-06-02
          • 2011-06-12
          • 1970-01-01
          相关资源
          最近更新 更多