如何在NestJS中结合Redis实现IP与请求体速率限制
实现NestJS多维度速率限制(IP+请求体字段)
问题分析
你当前的配置仅启用了单一维度的速率限制(默认按IP校验),触发限流后会拦截所有请求,无法同时实现IP和请求体字段(如用户名)两个维度的校验——只要任一维度达到阈值就返回429。
正确实现步骤
1. 自定义ThrottlerGuard
重写handleRequest方法,同时生成IP和请求体字段的限流标识,分别校验两个维度的请求次数,任一维度超标就触发429。
// src/common/guards/multi-throttler.guard.ts import { ThrottlerGuard } from '@nestjs/throttler'; import { ExecutionContext, Injectable } from '@nestjs/common'; @Injectable() export class MultiThrottlerGuard extends ThrottlerGuard { async handleRequest(context: ExecutionContext, limit: number, ttl: number): Promise<boolean> { const request = context.switchToHttp().getRequest(); // 生成IP维度的限流标识 const ipTracker = this.getTracker(request); // 生成请求体用户名维度的限流标识(根据实际字段名调整) const usernameTracker = request.body?.username ? `username:${request.body.username}` : null; // 校验IP维度限流 const ipRequestCount = await this.storage.increment(ipTracker, ttl); if (ipRequestCount > limit) { return false; } // 校验用户名维度限流(存在用户名时才校验) if (usernameTracker) { const usernameRequestCount = await this.storage.increment(usernameTracker, ttl); if (usernameRequestCount > limit) { return false; } } return true; } }
2. 替换全局Guard配置
在对应的业务Module中,把默认的ThrottlerGuard替换为自定义的多维度Guard:
// 对应业务Module.ts import { APP_GUARD } from '@nestjs/core'; import { MultiThrottlerGuard } from './common/guards/multi-throttler.guard'; @Module({ providers: [ { provide: APP_GUARD, useClass: MultiThrottlerGuard, }, ], }) export class YourBusinessModule {}
3. 调整ThrottlerModule全局配置
保留Redis存储配置,可根据需求设置全局默认的限流参数,也能在控制器上通过注解覆盖:
// app.module.ts import { ThrottlerModule } from '@nestjs/throttler'; import { ThrottlerStorageRedisService } from 'nestjs-throttler-storage-redis'; import Redis from 'ioredis'; @Module({ imports: [ ThrottlerModule.forRoot({ ttl: Number(process.env.IP_VELOCITY_TTL) || 86400, // 默认24小时(秒) limit: Number(process.env.IP_VELOCITY_COUNT) || 100, // 默认单维度请求次数 storage: new ThrottlerStorageRedisService(new Redis({ host: process.env.REDIS_HOST || 'localhost', port: Number(process.env.REDIS_PORT) || 6379, // 可添加Redis密码、数据库等配置 })), }), ], }) export class AppModule {}
4. 控制器路由配置
在需要限流的路由上,用@Throttle注解设置该路由的专属限流规则:
// controller.ts import { Throttle } from '@nestjs/throttler'; import { Controller, Post, Body } from '@nestjs/common'; @Controller('auth') export class AuthController { @Post('login') @Throttle(3, 3600) // 1小时内,IP或用户名维度最多请求3次 async login(@Body() loginDto: { username: string; password: string }) { // 登录业务逻辑 return { message: '登录成功' }; } }
关键说明
- 两个维度的限流标识相互独立,分别存储在Redis中,互不干扰
- 只要IP或用户名任一维度的请求次数超过设定阈值,就会返回429错误
- 如果请求体中无目标字段(如部分公共接口),仅会校验IP维度的限流
内容的提问来源于stack exchange,提问作者CandleCoder
相关产品推荐
相关产品推荐

