ASP.NET Core 8+固定窗口限流需用AddFixedWindowLimiter注册策略并配合UseRateLimiter启用,滑动窗口原生不支持,须自定义或借助Redis等外部存储实现。

固定窗口限流用 RateLimitingMiddleware 配合 FixedWindowRateLimiter
ASP.NET Core 8+ 内置的限流中间件默认不启用任何策略,必须显式注册并配置。固定窗口的核心是“每 N 秒重置计数”,比如每 60 秒最多 100 次请求。
常见错误是只调用 AddRateLimiter 却没指定具体策略类型,导致运行时报 InvalidOperationException: No rate limiter policy is configured。
- 在
Program.cs中注册时,必须用AddFixedWindowLimiter并传入策略名(如"fixed")和配置委托 -
Window单位是TimeSpan,写成TimeSpan.FromMinutes(1)比硬写60000毫秒更安全 - 注意
PermitLimit是窗口内总允许请求数,不是并发数;超限后默认返回 429,且不排队
builder.Services.AddRateLimiter(options =>
{
options.AddFixedWindowLimiter("fixed", options =>
{
options.Window = TimeSpan.FromMinutes(1);
options.PermitLimit = 100;
options.QueueProcessingOrder = QueueProcessingOrder.OldestFirst;
options.QueueLimit = 0; // 不排队,直接拒绝
});
});
滑动窗口限流需手动实现或换用第三方库
ASP.NET Core 原生 RateLimiter 目前(.NET 8 / 9 Preview)**不提供内置滑动窗口限流器**。官方只实现了 FixedWindowRateLimiter 和 SlidingWindowRateLimiter 的抽象基类,但后者未公开具体实现。
这意味着你不能像固定窗口那样直接调用 AddSlidingWindowLimiter —— 它根本不存在于 RateLimiterOptions 扩展方法中。
- 若坚持用原生方案,只能基于
IServerRateLimiter自定义实现,需维护时间分片(如 10 个 6 秒桶),处理跨桶聚合,逻辑复杂且易出错 - 更现实的做法是引入
AspNetCoreRateLimit(已归档)或Microsoft.Extensions.Resilience中的RateLimiter(.NET 8+ 实验性 API,仍不稳定) - 生产环境推荐用
StackExchange.Redis+ Lua 脚本实现分布式滑动窗口,避免内存泄漏和节点间不同步
中间件启用时必须指定策略名,且顺序不能错
注册完策略只是第一步,中间件本身需要明确告诉它“对哪些请求应用哪个策略”。漏掉 UseRateLimiter 或策略名拼错,限流完全不生效,连日志都不会打。
-
UseRateLimiter()必须放在UseRouting()之后、UseEndpoints()之前 - 策略名(如
"fixed")要和注册时完全一致,大小写敏感 - 若想按路由或 Header 区分策略,得用
ConfigureRateLimiter+EndpointRateLimiter,而不是全局统一策略
app.UseRouting();
app.UseRateLimiter(); // 必须在这里
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers().RequireRateLimiting("fixed");
});
滑动窗口的“平滑”特性容易被误读为“更宽松”
滑动窗口不是简单地把固定窗口切碎再叠加,它的计数是动态滚动的:例如“每 60 秒最多 100 次”,第 59 秒发起的请求会同时计入第 1 秒和第 60 秒两个窗口片段,实际允许短时突发更高——但这不是 bug,是设计使然。
如果你发现滑动窗口比预期放行更多请求,先确认是否混淆了“窗口长度”和“滑动粒度”。比如 Redis 实现中用 6 秒分片 × 10 片 = 60 秒窗口,但每个请求只更新当前分片,查询时 sum 最近 10 个分片值。这个 sum 过程如果没原子执行,就会出现竞态漏计。
- 单机滑动窗口用
ConcurrentDictionary加锁维护,性能差、GC 压力大,不建议 - 真正可靠的滑动窗口几乎都依赖外部存储(Redis、SQL Server 的行级锁 + TTL)
- 别为了“听起来高级”强行上滑动窗口——固定窗口在多数 API 场景下更稳定、更容易监控和调试










