在后台管理系统与高并发服务中,接口限流是必备的安全防护手段,用于防止恶意请求、暴力破解、CC 攻击,保障服务稳定性。本文将带你基于 NestJS + Redis 原子操作 实现企业级限流守卫,支持接口维度隔离、自动拉黑、跳过限流装饰器,功能媲美若依框架且更安全。
核心实现
1、创建限流常量
typescript
// src\common\constant\decorator.constant.ts
export const DecoratorConstant = {
// ...其他常量
/** 跳过接口限流 */
SKIP_THROTTLE: 'common:request:skipThrottle',
}
// src\common\constant\redis.constant.ts
export class RedisConstant {
// ...其他常量
/**
* 接口限流 Key 前缀
* 拼接客户端IP + 接口路径形成唯一Key,格式为「throttle:limit:ip:接口路径」
* 用于接口维度的请求频率限制与IP临时拉黑
*/
public static THROTTLE_LIMIT = 'throttle:limit'
}
2、创建跳过限流装饰器
typescript
// src\common\decorator\skip-throttle.decorator.ts
import { SetMetadata } from '@nestjs/common'
import { DecoratorConstant } from '../constant/decorator.constant'
/**
* 跳过接口限流装饰器
* 用于控制器或接口方法,标记后不受限流保护拦截
*/
export function SkipThrottle() {
return SetMetadata(DecoratorConstant.SKIP_THROTTLE, true)
}
3、创建限流核心守卫
typescript
import { Reflector } from '@nestjs/core'
import { RedisService } from '@/shared/redis.service'
import { SharedService } from '@/shared/shared.service'
import { RedisConstant } from '../constant/redis.constant'
import { DecoratorConstant } from '../constant/decorator.constant'
import { BusinessException } from '../exception/business.exception'
import { ExecutionContext, Injectable, CanActivate } from '@nestjs/common'
@Injectable()
export class ThrottlerLimitGuard implements CanActivate {
/** 最大允许请求次数 */
private readonly MAX_REQUESTS: number = 10
/** 限流时间窗口(秒) */
private readonly WINDOW_SECONDS: number = 10
/** 触发限流后拉黑时长(秒) */
private readonly LOCK_SECONDS: number = 60 * 30
constructor(
private readonly reflector: Reflector,
private readonly redisService: RedisService,
private readonly sharedService: SharedService,
) {}
async canActivate(context: ExecutionContext): Promise<boolean> {
const handler = context.getHandler()
const controllerClass = context.getClass()
const request = context.switchToHttp().getRequest<ExpressRequest>()
const ip = this.sharedService.getRequestIp(request)
const path = request.route?.path || request.url
// 判断是否跳过限流
const skipThrottle = this.reflector.getAllAndOverride<boolean>(DecoratorConstant.SKIP_THROTTLE, [handler, controllerClass])
if (skipThrottle) return true
if (!ip) throw new BusinessException('无法获取客户端 IP')
// 接口维度 + IP 限流(安全隔离)
const key = `${RedisConstant.THROTTLE_LIMIT}:${ip}:${path}`
// 检查是否被拉黑
const data = await this.redisService.get(key)
if (data === 'locked') throw new BusinessException('请求过于频繁,请稍后再试')
// 原子自增(高并发安全)
const count = await this.redisService.incr(key)
// 第一次设置过期时间
if (count === 1) await this.redisService.expire(key, this.WINDOW_SECONDS)
// 超过限制 → 拉黑 30 分钟
if (count > this.MAX_REQUESTS) {
await this.redisService.set(key, 'locked', 'EX', this.LOCK_SECONDS)
throw new BusinessException('请求过于频繁,请稍后再试')
}
return true
}
}
4、全局注册守卫
typescript
// src\app.module.ts
import { APP_GUARD } from '@nestjs/core'
import { ThrottlerLimitGuard } from '@/common'
@Module({
providers: [
// 注册全局接口限流守卫
{ provide: APP_GUARD, useClass: ThrottlerLimitGuard },
],
})
export class AppModule {}
5、装饰器使用示例
typescript
import { SkipThrottle } from '@/common'
// 控制器单个接口跳过限流
@Get('info')
@SkipThrottle()
getUserInfo() {
return this.userService.getInfo()
}
// 整个控制器跳过限流
@Controller('public')
@SkipThrottle()
export class PublicController {}
工作原理
- 维度隔离 :使用
IP + 接口路径生成唯一 Key,不同接口独立限流,互不干扰 - 原子操作 :基于 Redis
INCR实现原子自增,彻底解决高并发下计数不准问题 - 智能拉黑:请求超限后自动将 IP 临时拉黑,拒绝恶意攻击
- 灵活控制:支持全局 / 控制器 / 接口三级跳过限流,适配不同业务场景
- 安全提示:不暴露具体限流时长,避免给攻击者提供规则信息
核心优势
- ✅ 高并发安全:Redis 原子操作,无计数错乱问题
- ✅ 接口维度隔离:精准控制单接口访问频率
- ✅ 自动封禁:超限自动拉黑,防护能力拉满
- ✅ 无侵入设计:基于守卫 + 装饰器,不污染业务代码
- ✅ 全局生效:一次配置,全接口自动防护
- ✅ 灵活跳过:支持指定接口 / 控制器不限流
使用效果
- 正常请求:10 秒内≤10 次,正常访问
- 请求超限:触发限流,返回友好提示
- 超限多次:自动拉黑当前 IP 30 分钟
- 标记跳过 :
@SkipThrottle装饰的接口不受任何限制
总结
本文基于 NestJS 与 Redis 实现的接口限流守卫,仅需少量代码即可完成企业级安全防护 ,完美解决接口防刷、暴力攻击、恶意请求等问题。 相比 @nestjs/throttler 官方库,本方案更轻量、更安全、更贴合国内后台管理系统需求,可直接应用于生产环境,是后端服务必备的安全组件。