当前有一个 NuGet 包可以通过 IP 地址管理速率限制,称为 AspNetCoreRateLimit。然而,.NET 7 引入了自己的速率限制版本,我想使用它,因为它是由 MS 发布的。我还没有找到一个通过 IP 地址限制来模仿这个第三方包的好例子。我整理的代码如下:
builder.Services.AddRateLimiter(options =>
{
options.RejectionStatusCode = 429;
options.AddPolicy("api", httpContext =>
{
var IpAddress = httpContext.Connection.RemoteIpAddress.ToString();
if (IpAddress != null)
{
return RateLimitPartition.GetFixedWindowLimiter(httpContext.Connection.RemoteIpAddress.ToString(),
partition => new FixedWindowRateLimiterOptions
{
AutoReplenishment = true,
PermitLimit = 5,
Window = TimeSpan.FromMinutes(1)
});
}
else
{
return RateLimitPartition.GetNoLimiter("");
}
});
});
但是,我收到的问题是警告“警告 CS8602:取消引用可能为空的引用。”我认为这是因为 RemoteIpAddress 可能为空。我很好奇是否有更好的方法来使用这个新的 .NET 7 库来实现 IP 速率限制。如果重要的话,我计划在 Azure 应用程序服务(Windows)中托管此 Web api,并由同样托管在应用程序服务中的 SPA 访问它。
正如您所提到的,有关可能为空引用的引用的警告实际上并不是错误。它确实来自这一行:
httpContext.Connection.RemoteIpAddress.ToString()
因为 RemoteIpAddress 属性可以为 null(因此您的 ToString() 调用将抛出异常)。
但是,(在我看来)这与您的实际问题无关,即: “我很好奇是否有更好的方法来使用这个新的 .NET 7 库来实现 IP 速率限制”
微软文档中直接有一个这样的例子: https://learn.microsoft.com/en-us/aspnet/core/performance/rate-limit?view=aspnetcore-7.0#limiter-with-onrejected-retryafter-and-globallimiter
具体可以在该页面找到此代码:
limiterOptions.GlobalLimiter = PartitionedRateLimiter.Create<HttpContext, IPAddress>(context =>
{
IPAddress? remoteIpAddress = context.Connection.RemoteIpAddress;
if (!IPAddress.IsLoopback(remoteIpAddress!))
{
return RateLimitPartition.GetTokenBucketLimiter
(remoteIpAddress!, _ =>
new TokenBucketRateLimiterOptions
{
TokenLimit = myOptions.TokenLimit2,
QueueProcessingOrder = QueueProcessingOrder.OldestFirst,
QueueLimit = myOptions.QueueLimit,
ReplenishmentPeriod = TimeSpan.FromSeconds(myOptions.ReplenishmentPeriod),
TokensPerPeriod = myOptions.TokensPerPeriod,
AutoReplenishment = myOptions.AutoReplenishment
});
}
return RateLimitPartition.GetNoLimiter(IPAddress.Loopback);
});
这个特定的代码正在设置一个全局限制器(有点偏离重点),但是如果你看看他们建议的方法,它确实与你所拥有的类似。
他们没有转换为字符串,而是以不同的方式进行检查。如果您想坚持使用字符串并摆脱警告,您可能可以使用以下内容:
var ipAddressAsString = httpContext.Connection.RemoteIpAddress?.ToString();
我们在哪里有?正在使用的运算符。无论如何,我认为您的方法是正确的。