如何返回 202 Accepted 然后在 Nest.js 中继续处理请求

For*_*eti 7 javascript asynchronous long-running-processes node.js nestjs

我需要一个控制器操作:

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

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

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

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

Kim*_*ern 8

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

@Injectable()
export class ExternalApiService {
  constructor(private readonly httpService: HttpService) {}

  makeApiCall(data): Observable<AxiosResponse<any>> {
    return this.httpService.post('https://external.api', data);
  }
}
Run Code Online (Sandbox Code Playgroud)

我还假设有一个 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.';
}
Run Code Online (Sandbox Code Playgroud)

当您进行异步调用时,您的控制器方法的执行只会等待,如果您通过使用async/await或返回 a Promise/ an明确告诉它Observable

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

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


Ric*_*can 7

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

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