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)才会写入 限流策略本身不难配,真正复杂的是键的设计粒度、跨进程状态同步、以及拒绝时的用户体验衔接——比如是否返回友好的 JSON 错误体,而不是裸 429 HTML 页面。
