【问题标题】:How to return 202 Accepted and then continue processing the request in Nest.js如何返回 202 Accepted 然后继续在 Nest.js 中处理请求
【发布时间】:2018-11-08 10:14:01
【问题描述】:

我需要一个控制器动作:

  1. 授权调用
  2. 验证它
  3. 返回 202 Accepted 状态
  4. 继续处理请求
  5. 使用先前接受和现在处理的请求的结果调用外部 API。

前两点很简单,我使用AuthGuard 然后class-validator。但我不知道如何返回 HTTP 响应然后继续处理。

由于请求由一组(可能长时间运行的)任务组成,我想到使用拦截器,该拦截器使用 RxJS 来观察任务的状态并在完成后调用外部 PI。但是,我没有使用 RxJS 或拦截器(不是这种方式)的经验,所以我真的不知道如何让拦截器的进程运行,但立即将控制权传递给控制器​​的操作。

另外,也许还有另一种更好的方法?没有拦截器,只是将所有流逻辑放在控制器中?还有其他选择吗?

【问题讨论】:

    标签: javascript node.js asynchronous nestjs long-running-processes


    【解决方案1】:

    我希望您有一个执行外部 API 调用(异步)并返回 PromiseObservable 的服务:

    @Injectable()
    export class ExternalApiService {
      constructor(private readonly httpService: HttpService) {}
    
      makeApiCall(data): Observable<AxiosResponse<any>> {
        return this.httpService.post('https://external.api', data);
      }
    }
    

    我还假设有一个 PreprocesserService 进行异步调用(例如从数据库中获取用户信息)。

    控制器

    @Post()
    @UseGuards(AuthGuard('jwt'))
    @HttpCode(HttpStatus.ACCEPTED)
    async post(@Body(new ValidationPipe()) myDataDto: MyDataDto) {
      // The preprocessing might throw an exception, so we need to wait for the result
      const preprocessedData = await this.preprocessService.preprocess(myDataDto);
                               ^^^^^
      // We do not need the result to respond to the request, so no await
      this.externalApiService.makeApiCall(preprocessedData);
      return 'Your data is being processed.';
    }
    

    当您进行异步调用时,控制器方法的执行只有在您通过使用 async/await 或返回 Promise / Observable 明确告知它时才会等待。

    在本例中,我们希望在发送响应之前等待this.preprocessService.preprocess(myDataDto) 的结果。我们通过使用await 来做到这一点(该方法必须声明为async)。

    我们想向外部 API 发出请求,但我们的响应不需要结果。因为我们不是在这里使用await,所以它会进行http调用并立即执行下一行(return语句)而不等待结果。

    【讨论】:

    • 如果我想用它来调用内部 API,我绝对可以做一个完整的 http post,但不知道如何直接调用我的内部 observable 而无需等待它。
    • 回答我自己的评论,我的解决方案不是将可观察对象返回给嵌套控制器并依靠嵌套在幕后调用subscribe,而是直接在可观察对象上调用.subscribe()然后立即返回一个值
    • @KyleMit 抱歉,我回复晚了凯尔,过去几周我很忙。 -- 没错,这是一个不错的选择,很高兴您这么快就找到了解决方案。或者,如果您更喜欢使用 Promise,您也可以在 Observable 上致电 toPromise
    • 嗨,Kim,非常感谢您的回答和更新。我最初选择toPromise,但后来收到一些警告toPromise is being deprecated in v7 and removed in v8
    【解决方案2】:

    如果您的服务返回一个承诺,您可以执行以下操作,API 将在处理继续时返回 202。当然,任何带有 'then' 的处理都是在 'beginProcessing' 完成之后进行的。

    @Post()
    @HttpCode(HttpStatus.ACCEPTED)
    beginProcessing(@Req() request, @Body() data: Data): void {
        this.service.process(data).then(...);
    }
    

    【讨论】:

      猜你喜欢
      • 2019-09-01
      • 2022-12-20
      • 1970-01-01
      • 2015-12-02
      • 2014-10-06
      • 1970-01-01
      • 2022-12-14
      • 2010-12-01
      • 1970-01-01
      相关资源
      最近更新 更多