.NET 7限流:为指定端点实现按客户端区分的固定窗口限流
.NET 7 限流中间件:为指定端点配置按客户端区分的固定窗口限流
核心需求:
- 为2个公共端点分别配置独立的固定窗口限流规则
- 每个规则按客户端(用户ID/IP)独立计数限流,而非全局统一限制
- 仅作用于指定端点,不启用全局限流器
实现方案
1. 定义带客户端分区的命名限流策略
通过AddPolicy结合PartitionedRateLimiter.Create,创建既支持命名、又能按客户端分区的固定窗口限流规则:
builder.Services.AddRateLimiter(options => { // 为第一个公共端点配置限流策略:每个客户端30秒内允许5次请求 options.AddPolicy("PublicEndpoint1Limit", context => PartitionedRateLimiter.Create<HttpContext, string>(httpContext => RateLimitPartition.GetFixedWindowLimiter( // 用用户ID或IP作为分区键,确保每个客户端独立计数 partitionKey: httpContext.User.Identity?.Name ?? httpContext.Connection.RemoteIpAddress?.ToString() ?? "anonymous", factory: _ => new FixedWindowRateLimiterOptions { AutoReplenishment = true, PermitLimit = 5, Window = TimeSpan.FromSeconds(30), QueueLimit = 0 // 拒绝超出限制的请求,不排队 }))); // 为第二个公共端点配置不同的限流策略:每个客户端60秒内允许10次请求 options.AddPolicy("PublicEndpoint2Limit", context => PartitionedRateLimiter.Create<HttpContext, string>(httpContext => RateLimitPartition.GetFixedWindowLimiter( partitionKey: httpContext.User.Identity?.Name ?? httpContext.Connection.RemoteIpAddress?.ToString() ?? "anonymous", factory: _ => new FixedWindowRateLimiterOptions { AutoReplenishment = true, PermitLimit = 10, Window = TimeSpan.FromSeconds(60), QueueLimit = 0 }))); // 统一配置限流触发后的响应逻辑 options.OnRejected = (context, _) => { if (context.Lease.TryGetMetadata(MetadataName.RetryAfter, out var retryAfter)) { context.HttpContext.Response.Headers.RetryAfter = ((int)retryAfter.TotalSeconds).ToString(System.Globalization.NumberFormatInfo.InvariantInfo); var logger = context.HttpContext.RequestServices.GetRequiredService<ILogger<Program>>(); logger.LogWarning("客户端 {ClientKey} 触发限流,{RetryAfter}秒后可重试", context.PartitionKey, retryAfter.TotalSeconds); } context.HttpContext.Response.StatusCode = StatusCodes.Status429TooManyRequests; return ValueTask.CompletedTask; }; });
2. 将策略绑定到指定端点
在路由配置中,通过RequireRateLimiting为目标端点指定对应的限流策略:
// 第一个公共端点应用"PublicEndpoint1Limit"策略 app.MapGet("/public/api/v1/resource", () => Results.Ok("资源1响应")) .RequireRateLimiting("PublicEndpoint1Limit"); // 第二个公共端点应用"PublicEndpoint2Limit"策略 app.MapPost("/public/api/v1/submit", () => Results.Ok("提交成功")) .RequireRateLimiting("PublicEndpoint2Limit"); // 其他端点不受限流规则影响 app.MapGet("/internal/api/status", () => Results.Ok("内部状态正常"));
关键说明
- 分区键自定义:可以根据业务需求替换
partitionKey的取值(比如客户端ID、API密钥等),确保每个客户端的请求计数独立 - 策略独立性:每个命名策略可以配置不同的
PermitLimit、Window参数,满足不同端点的限流要求 - 拒绝响应定制:全局
OnRejected统一处理429响应,也可以为单个策略单独配置拒绝逻辑(通过AddPolicy的重载方法)
内容的提问来源于stack exchange,提问作者Platypus
相关产品推荐
相关产品推荐

