我正在尝试取消对超过 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/