.NET 7速率限制 - 按客户端进行速率限制

5

我需要使用.NET 7新的速率限制中间件来对公共端点实施速率限制。
目前,我已经选择了一个固定窗口速率限制器。 我在网上找到了许多不同的实现,但是我发现唯一实现任何IP/客户端过滤的是使用全局限制器,而我不想使用它。
我有很多端点,我希望在其中2个公共端点上使用2个不同的限制器。
我想要的是以下两种实现的混合体,它允许我命名策略以仅在端点上实施它,并且速率限制是每个客户端的。

我可以分配给每个端点的2个不同策略:

builder.Services.AddRateLimiter(options =>
{
    options.AddFixedWindowLimiter("myRateLimiter1", options =>
    {
        options.AutoReplenishment = true;
        options.PermitLimit = 1;
        options.Window = TimeSpan.FromSeconds(30);
    });
    options.AddFixedWindowLimiter("myRateLimiter12", options =>
    {
        options.AutoReplenishment = true;
        options.PermitLimit = 1;
        options.Window = TimeSpan.FromSeconds(30);
    });
});

全局实现的客户端过滤

builder.Services.AddRateLimiter(options =>
{
    options.GlobalLimiter = PartitionedRateLimiter.Create<HttpContext, string>(httpContext =>
        RateLimitPartition.GetFixedWindowLimiter(
            partitionKey: httpContext.User.Identity?.Name ?? httpContext.Request.Headers.Host.ToString(),
            factory: partition => new FixedWindowRateLimiterOptions
            {
                AutoReplenishment = true,
                PermitLimit = 1,
                QueueLimit = 0,
                Window = TimeSpan.FromSeconds(30)
            }));
});

我也找到了一个能够完成任务的实现,但是无法找到如何添加过滤器。

app.UseRateLimiter(new RateLimiterOptions
{
    OnRejected = (context, _) =>
    {
        if (context.Lease.TryGetMetadata(MetadataName.RetryAfter, out var retryAfter))
        {
            context.HttpContext.Response.Headers.RetryAfter =
                ((int)retryAfter.TotalSeconds).ToString(NumberFormatInfo.InvariantInfo);

            app.Logger.LogWarning("Rate limit exceeded, retry after {RetryAfter} seconds", retryAfter.TotalSeconds);
        }

        context.HttpContext.Response.StatusCode = StatusCodes.Status429TooManyRequests;

        return new ValueTask();
    }
}
.AddFixedWindowLimiter("myRateLimiter1", options =>
{
    options.AutoReplenishment = true;
    options.PermitLimit = 1;
    options.Window = TimeSpan.FromSeconds(10);
    options.QueueLimit = 0;
}).AddFixedWindowLimiter("myRateLimiter2", options =>
{
    options.AutoReplenishment = true;
    options.PermitLimit = 1;
    options.Window = TimeSpan.FromSeconds(10);
    options.QueueLimit = 0;
}));
1个回答

7

通过 RateLimiterOptions.AddPolicy 添加您的限制器:

builder.Services.AddRateLimiter(options =>
{
    options.AddPolicy("myRateLimiter1", context => RateLimitPartition.GetFixedWindowLimiter(
        partitionKey: context.User.Identity?.Name ?? context.Request.Headers.Host.ToString(),
        factory: partition => new FixedWindowRateLimiterOptions
        {
            AutoReplenishment = true,
            PermitLimit = 1,
            QueueLimit = 0,
            Window = TimeSpan.FromSeconds(30)
        }));
    // and the second one
});

看起来它正在做我想要的事情,感谢你的回答。 - Platypus

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接