ASP.NET Core 6+ 内置 AddRateLimiter 是首选方案,需正确注册服务、启用中间件、统一策略名,并按需选择 SlidingWindowLimiter 或 TokenBucketLimiter;自定义 KeyGenerator 可实现用户级限流;生产环境须用 RedisRateLimiter 并开启调试日志与响应头。

ASP.NET Core 6+ 内置 AddRateLimiter 是首选方案
ASP.NET Core 6 开始原生支持速率限制,无需第三方包(如 AspNetCoreRateLimit),配置更轻、扩展性更好。它基于策略(RateLimiterOptions)和限流器(如 SlidingWindowLimiter、TokenBucketLimiter)实现,与中间件生命周期深度集成。
常见错误是直接在 Program.cs 中调用 AddRateLimiter 后忘记启用中间件,或策略名称拼写不一致导致 429 不触发。
- 必须在
app.UseRateLimiter()之前注册服务,且顺序不能颠倒 - 策略名(如
"sliding")需与RequireRateLimiting("sliding")中的字符串完全一致 -
SlidingWindowLimiter更适合突发流量控制;TokenBucketLimiter更适合平滑匀速放行 - 限流键(
KeyGenerator)默认按客户端 IP,若需按 API key 或用户 ID,必须自定义HttpContext提取逻辑
SlidingWindowLimiter 配置关键参数说明
滑动窗口是最常用策略,但参数含义容易误解:PermitLimit 是窗口内允许请求数,Window 是窗口时长,而 QueueProcessingOrder 和 QueueLimit 控制排队行为——不是所有场景都需要排队。
-
PermitLimit = 100+Window = TimeSpan.FromMinutes(1)表示每分钟最多 100 次请求,不是“每 60 秒清零”,而是滚动统计 - 设置
QueueLimit = 10后,超出限流的请求会排队,但超时由QueueTimeout控制(默认 10 秒),超时仍返回 429 - 若禁用排队(
QueueLimit = 0),所有超额请求立即 429,响应更快,适合低延迟敏感接口 -
ReplenishmentPeriod仅对TokenBucketLimiter有效,滑动窗口中设了也无效
如何按用户身份(而非 IP)做限流
默认限流键只取 HttpContext.Connection.RemoteIpAddress,要切换到用户维度,必须重写 KeyGenerator,并在认证后读取用户标识。JWT 或 Cookie 认证均可支持,但要注意未认证请求的 fallback 处理。
- 在策略配置中传入自定义
KeyGenerator函数,例如提取HttpContext.User.FindFirst("sub")?.Value - 未登录用户建议 fallback 到 IP,避免匿名用户共享同一限流桶:用
HttpContext.User.Identity.IsAuthenticated ? userId : ip - 若使用
[Authorize]特性,确保UseAuthentication()在UseRateLimiter()之前调用,否则User为空 - 注意:
User对象在限流中间件执行时已解析完成,但自定义声明需在AddJwtBearer或AddCookie中显式映射
生产环境必须检查的三个隐藏问题
本地测试通过不代表线上可用。分布式部署、高并发压测、日志埋点缺失,常让限流失效却不报错。
- 默认内存限流器(
MemoryRateLimiter)不支持多实例共享状态,K8s 多 Pod 场景下必须换用RedisRateLimiter并注入IConnectionMultiplexer - 未开启详细日志时,限流拒绝不会输出任何信息,建议在
Program.cs中配置:builder.Logging.AddConsole().AddFilter("Microsoft.AspNetCore.RateLimiting", LogLevel.Debug) -
前端可能忽略
X-RateLimit-Remaining等响应头,但这些头默认不启用,需手动调用EnableRateLimitHeaders(true)才会写入










