Nest.js如何动态限制请求速率
Nest.js 使用 @nestjs/throttler 时如何动态限制请求速率?
场景:有个 API,平常限制请求速率为 1 分钟 1 次,现在业务有个场景:如果符合某个条件就暂时放开限制,客户端可以立即再次发起请求,服务端再次判断,如果不再符合条件了,就再限制上请求速率。
@nestjs/throttler
默认使用装饰器,没办法完成上面的需求。查看源码,发现装饰器的核心代码如下:// throttler.decorator.ts export const Throttle = (limit = 20, ttl = 60): MethodDecorator & ClassDecorator => { return ( target: any, propertyKey?: string | symbol, descriptor?: TypedPropertyDescriptor<any>, ) => { if (descriptor) { setThrottlerMetadata(descriptor.value, limit, ttl); return descriptor; } setThrottlerMetadata(target, limit, ttl); return target; }; }; // throttler.decorator.ts export const SkipThrottle = (skip = true): MethodDecorator & ClassDecorator => { return ( target: any, propertyKey?: string | symbol, descriptor?: TypedPropertyDescriptor<any>, ) => { if (descriptor) { Reflect.defineMetadata(THROTTLER_SKIP, skip, descriptor.value); return descriptor; } Reflect.defineMetadata(THROTTLER_SKIP, skip, target); return target; }; };
发现是通过定义元数据来实现是否限制速率,知道这些,就可以在业务逻辑中手动设置了。
先把
@nestjs/throttler
引用的常量单独提出来:// throttler.constant.ts export const THROTTLER_LIMIT = 'THROTTLER:LIMIT'; export const THROTTLER_TTL = 'THROTTLER:TTL'; export const THROTTLER_SKIP = 'THROTTLER:SKIP';
再根据业务逻辑单独设置:
// auth.controller.ts @Controller('auths') export class AuthController { @Throttle(1, 60) @Post('confirmation') async sendConfirmation(@Body('email') email: string) { const self = this.sendConfirmation; if (userIsExist) { // 设置元数据,忽略请求速率的限制 Reflect.defineMetadata(THROTTLER_SKIP, true, self); throw new BadRequestException('用户已存在'); } else { // 重新设置限制 Reflect.defineMetadata(THROTTLER_SKIP, false, self); } return this.authService.sendConfirmation(email); } }