javascript - 无法在拦截器中取消请求

标签 javascript rxjs nestjs

我正在尝试取消超过 n 秒的请求的请求处理。例如,在此示例中https://github.com/nestjs/nest/tree/master/sample/01-cats-app

cats.controller.ts中替换

@UseInterceptors(LoggingInterceptor, TransformInterceptor)

@UseInterceptors(TimeoutInterceptor, LoggingInterceptor, TransformInterceptor)

cats.controller.ts中替换

  @Get()
  async findAll(): Promise<Cat[]> {
    return this.catsService.findAll();
  }

  @Get()
  async findAll(): Promise<Cat[]> {
    for (let i = 0; i < 100000000; i++) {
      if (i === 99999999) {
        return this.catsService.findAll();
      }
    }
  }

添加拦截器源码:

import {
  CallHandler,
  ExecutionContext,
  Injectable,
  NestInterceptor,
} from '@nestjs/common';
import { Observable } from 'rxjs';
import { timeout } from 'rxjs/operators';

@Injectable()
export class TimeoutInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    return next.handle().pipe(timeout(1));
  }
}

即使在 1 毫秒后也会处理请求并返回数据。日志:

Before...
After... 134ms

拦截器的代码来自这里:https://docs.nestjs.com/interceptors

我做错了什么?

最佳答案

好的,知道发生了什么了。当按照您现在的方式使用 for 循环时,从技术上讲,您并没有进入执行上下文的下一部分,因此超时管道尚未开始生效。为了启动超时运算符,必​​须调用 AppService 的方法以允许调用堆栈继续前进。您可以返回一个异步函数,并让可观察的工作及其超时与异步函数的工作时间相对应,但 for 循环通常是同步的,这就是错误功能出现的地方。如果您愿意,请尝试添加

function asyncTimeout(time: number) {
  return new Promise((resolve, reject) => {
    setTimeout(() => resolve(), time);
  });
}

将此函数发送到您的服务器,然后调用await asyncTimeout(5000)

您可以将其用于您的AppService

import { Injectable } from '@nestjs/common';

function asyncTimeout(time: number) {
  return new Promise((resolve, reject) => {
    setTimeout(() => resolve(), time);
  });
}

@Injectable()
export class AppService {
  async getHello(): Promise<string> {
    console.log('In service');
    await asyncTimeout(5000);
    console.log('Returning after waiting');
    return 'Hello World!';
  }
}

这适用于您的AppController

import { Controller, Get, UseInterceptors } from '@nestjs/common';
import { AppService } from './app.service';
import { TimeoutInterceptor } from './timeout.interceptor';

@Controller()
@UseInterceptors(TimeoutInterceptor)
export class AppController {
  constructor(private readonly appService: AppService) {}

  @Get()
  getHello(): Promise<string> {
    console.log('In controller');
    return this.appService.getHello();
  }
}

并将其作为您的TimeoutInterceptor

import { CallHandler, ExecutionContext, Injectable, NestInterceptor } from '@nestjs/common';
import { Observable } from 'rxjs';
import { tap, timeout } from 'rxjs/operators';

@Injectable()
export class TimeoutInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    console.log('In interceptor');
    return next.handle().pipe(tap(() => console.log('In tap of return interceptor')), timeout(1));
  }
}

如果您调用http://localhost:3000,您将看到超时几乎立即发生,并且您将看到日志:

[Nest] 10529   - 12/23/2019, 8:07:40 AM   [NestFactory] Starting Nest application...
[Nest] 10529   - 12/23/2019, 8:07:40 AM   [InstanceLoader] AppModule dependencies initialized +11ms
[Nest] 10529   - 12/23/2019, 8:07:40 AM   [RoutesResolver] AppController {/}: +4ms
[Nest] 10529   - 12/23/2019, 8:07:40 AM   [RouterExplorer] Mapped {/, GET} route +2ms
[Nest] 10529   - 12/23/2019, 8:07:40 AM   [NestApplication] Nest application successfully started +2ms
In interceptor
In controller
In service
[Nest] 10529   - 12/23/2019, 8:07:48 AM   [ExceptionsHandler] Timeout has occurred +7955ms
Returning after waiting

但是在 HTTP 响应中你会发现

▶ curl http://localhost:3000
{"statusCode":500,"message":"Internal server error"}% 

这是因为您无法取消 promise ,因此它仍必须完成其执行。但是,您可以忽略 promise 的返回,因为您已经向客户端发送了响应,表示请求花费的时间太长。

Here's a link to the repository

关于javascript - 无法在拦截器中取消请求,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59450028/

相关文章:

javascript - 选项卡无法正常工作

angular - 如何更新使用 of(myArray) 创建的 RxJS Observable 的值

nestjs - 无法使用nestjs和nodemailer发送电子邮件

node.js - 如何使用@ResolveField 在 nestjs/graphql 中创建多级嵌套查询?

javascript - Nest.js 部署到 now.sh

javascript - 如何在md-switch的两侧放置文本?

javascript - 如何使用 JavaScript 在 Internet Explorer 9 中定位一个 div?

javascript - 在 Javascript 中循环遍历 Photoshop 图层

javascript - 如何: request the url and zip it with response in rxjs?

angular - 在 AngularFire 和 Angularjs 2 中编写路由守卫以等待身份验证