You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 23:15:35