Nest的限流方案

文章目录

  • 前言
      • ✅ 1. 使用 `@nestjs/throttler` 配置基础限流(适用于单节点)
        • `app.module.ts`
        • 在控制器中使用装饰器限流
      • ✅ 2. Redis 限流器(适配集群)
        • 替换默认存储为 RedisStorage
      • ✅ 3. 高级限流策略(自定义限流 Key)
      • ✅ 4. 接入 Metrics + 日志告警
      • ✅ 5. 限流白名单机制
      • ✅ 总结:实践核心要点


前言

项目中,NestJS 的限流(Rate Limiting)不仅仅是简单的限速控制,而是强调:

  • 多维度限流(如 IP、用户 ID、接口级别、请求类型)
  • 可配置化(支持不同环境和接口动态配置)
  • 可观测性(接入日志、监控系统)
  • 高性能和分布式支持(Redis 限流器)
  • 与鉴权鉴权链路集成(结合 JWT、API Token)

以下是一个“标准”的 NestJS 限流方案:


✅ 1. 使用 @nestjs/throttler 配置基础限流(适用于单节点)

pnpm add @nestjs/throttler
app.module.ts
import { ThrottlerModule } from '@nestjs/throttler';

@Module({
  imports: [
    ThrottlerModule.forRoot({
      ttl: 60,             // 每 60 秒窗口
      limit: 10,           // 允许 10 次请求
    }),
  ],
})
export class AppModule {}
在控制器中使用装饰器限流
import { Throttle } from '@nestjs/throttler';

@Controller('auth')
export class AuthController {
  @Throttle(5, 60) // 自定义:60秒内最多请求5次
  @Post('login')
  login(@Body() dto: LoginDto) {
    // ...
  }
}

✅ 2. Redis 限流器(适配集群)

单实例的 MemoryThrottlerStorage 无法满足分布式部署,推荐使用 Redis:

pnpm add cache-manager-ioredis ioredis
替换默认存储为 RedisStorage
import { ThrottlerModule } from '@nestjs/throttler';
import { ThrottlerStorageRedisService } from 'nestjs-throttler-storage-redis';

@Module({
  imports: [
    ThrottlerModule.forRootAsync({
      useFactory: () => ({
        ttl: 60,
        limit: 10,
        storage: new ThrottlerStorageRedisService({
          host: 'localhost',
          port: 6379,
        }),
      }),
    }),
  ],
})
export class AppModule {}

可封装配置为 .env 动态环境变量 + config.module


✅ 3. 高级限流策略(自定义限流 Key)

自定义根据用户ID、IP、接口路径来限流:

import { ThrottlerGuard, ThrottlerModuleOptions } from '@nestjs/throttler';
import { ExecutionContext, Injectable } from '@nestjs/common';

@Injectable()
export class CustomThrottlerGuard extends ThrottlerGuard {
  protected getTracker(req: Request): string {
    const user = (req as any).user;
    return user?.id || req.ip; // 优先按用户ID限流,否则按IP
  }

  protected getRequestResponse(context: ExecutionContext) {
    const ctx = context.switchToHttp();
    return { req: ctx.getRequest(), res: ctx.getResponse() };
  }
}

main.ts 或某个模块中启用:

app.useGlobalGuards(new CustomThrottlerGuard());

✅ 4. 接入 Metrics + 日志告警

将限流被拒绝的事件记录到:

  • 日志系统(如 Winston + Elasticsearch)
  • 监控系统(如 Prometheus + Grafana)
  • 告警系统(如钉钉、飞书、PagerDuty)

你可以在自定义 Guard 中拦截超限的请求并发送日志:

protected throwThrottlingException(context: ExecutionContext): void {
  const req = context.switchToHttp().getRequest();
  console.warn(`[RateLimit] Blocked: ${req.ip}, Path: ${req.url}`);
  super.throwThrottlingException(context);
}

✅ 5. 限流白名单机制

如某些 IP 或用户角色无需限流,可添加白名单判断:

if (['127.0.0.1', 'admin-user-id'].includes(req.ip || user?.id)) {
  return false; // skip throttling
}

✅ 总结:实践核心要点

维度 建议
限流存储 推荐 Redis 支持多实例
限流 Key 设计 支持 IP + 用户ID + 路由等多种维度
限流策略 精细化配置,接口粒度调整
异常处理 自定义响应体、日志告警
观测性 打通 Prometheus / Grafana / ELK 等链路

你可能感兴趣的:(node.js,架构,node.js)