在 ASP.NET Core 中實現速率限制(Rate Limiting)中間件可以幫助你控制客戶端對 API 的請求頻率,防止濫用和過載。速率限制通常用于保護服務器資源,確保服務的穩定性和可用性。
ASP.NET Core 本身并沒有內置的速率限制中間件,但你可以通過自定義中間件或使用第三方庫來實現速率限制。以下是實現速率限制的幾種常見方法:
1. 使用自定義中間件實現速率限制
你可以通過自定義中間件來實現速率限制。以下是一個簡單的實現示例:
1.1 實現速率限制中間件
using Microsoft.AspNetCore.Http;
using System.Collections.Concurrent;
using System.Threading.Tasks;
public class RateLimitingMiddleware
{
private readonly RequestDelegate _next;
private readonly int _maxRequests;
private readonly ConcurrentDictionary<string, RateLimiter> _rateLimiters;
public RateLimitingMiddleware(RequestDelegate next, int maxRequests)
{
_next = next;
_maxRequests = maxRequests;
_rateLimiters = new ConcurrentDictionary<string, RateLimiter>();
}
public async Task InvokeAsync(HttpContext context)
{
var clientId = context.Connection.RemoteIpAddress.ToString();
var rateLimiter = _rateLimiters.GetOrAdd(clientId, _ => new RateLimiter(_maxRequests));
if (rateLimiter.AllowRequest())
{
await _next(context);
}
else
{
context.Response.StatusCode = StatusCodes.Status429TooManyRequests;
await context.Response.WriteAsync("請求太多。請稍后再試.");
}
}
}
public class RateLimiter
{
private readonly int _maxRequests;
private int _requestCount;
private DateTime _windowStart;
public RateLimiter(int maxRequests)
{
_maxRequests = maxRequests;
_requestCount = 0;
_windowStart = DateTime.UtcNow;
}
public bool AllowRequest()
{
var now = DateTime.UtcNow;
if ((now - _windowStart).TotalSeconds > 60)
{
_requestCount = 0;
_windowStart = now;
}
if (_requestCount < _maxRequests)
{
_requestCount++;
return true;
}
return false;
}
}
1.2 注冊中間件
在 Startup.cs
中注冊中間件:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseMiddleware<RateLimitingMiddleware>(10);
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
2. 使用第三方庫實現速率限制
如果你不想自己實現速率限制邏輯,可以使用一些現成的第三方庫,例如:
2.1 AspNetCoreRateLimit
AspNetCoreRateLimit 是一個流行的 ASP.NET Core 速率限制庫,支持 IP 地址、客戶端 ID 和端點級別的速率限制。
安裝
通過 NuGet 安裝:
dotnet add package AspNetCoreRateLimit
配置
在 Startup.cs
中配置速率限制:
public void ConfigureServices(IServiceCollection services)
{
services.AddMemoryCache();
services.Configure<IpRateLimitOptions>(Configuration.GetSection("IpRateLimiting"));
services.AddSingleton<IIpPolicyStore, MemoryCacheIpPolicyStore>();
services.AddSingleton<IRateLimitCounterStore, MemoryCacheRateLimitCounterStore>();
services.AddSingleton<IRateLimitConfiguration, RateLimitConfiguration>();
services.AddSingleton<IProcessingStrategy, AsyncKeyLockProcessingStrategy>();
services.AddInMemoryRateLimiting();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseIpRateLimiting();
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
配置文件
在 appsettings.json
中添加速率限制配置:
{
"IpRateLimiting": {
"EnableEndpointRateLimiting": true,
"StackBlockedRequests": false,
"RealIpHeader": "X-Real-IP",
"ClientIdHeader": "X-ClientId",
"GeneralRules": [
{
"Endpoint": "*",
"Period": "1m",
"Limit": 10
}
]
}
}
3. 使用分布式緩存實現速率限制
如果你的應用是分布式的(例如部署在 Kubernetes 或多個服務器上),可以使用分布式緩存(如 Redis)來實現速率限制。
3.1 使用 Redis 實現速率限制
你可以使用 Redis 來存儲每個客戶端的請求計數。以下是一個簡單的示例:
using Microsoft.AspNetCore.Http;
using StackExchange.Redis;
using System.Threading.Tasks;
public class RedisRateLimitingMiddleware
{
private readonly RequestDelegate _next;
private readonly int _maxRequests;
private readonly ConnectionMultiplexer _redis;
public RedisRateLimitingMiddleware(RequestDelegate next, int maxRequests, ConnectionMultiplexer redis)
{
_next = next;
_maxRequests = maxRequests;
_redis = redis;
}
public async Task InvokeAsync(HttpContext context)
{
var clientId = context.Connection.RemoteIpAddress.ToString();
var db = _redis.GetDatabase();
var key = $"rate_limit:{clientId}";
var requestCount = await db.StringIncrementAsync(key);
if (requestCount == 1)
{
await db.KeyExpireAsync(key, TimeSpan.FromMinutes(1));
}
if (requestCount > _maxRequests)
{
context.Response.StatusCode = StatusCodes.Status429TooManyRequests;
await context.Response.WriteAsync("請求太多。請稍后再試.");
}
else
{
await _next(context);
}
}
}
3.2 注冊中間件
在 Startup.cs
中注冊中間件:
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<ConnectionMultiplexer>(ConnectionMultiplexer.Connect("localhost:6379"));
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseMiddleware<RedisRateLimitingMiddleware>(10);
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
4. 總結
在 ASP.NET Core 中實現速率限制有多種方式:
- 自定義中間件:適合簡單的場景,但需要自己實現邏輯。
- 第三方庫:如 AspNetCoreRateLimit,提供了更強大的功能和靈活性。
- 分布式緩存:如 Redis,適合分布式環境。
根據你的需求選擇合適的方式,確保你的 API 能夠有效防止濫用和過載。
?轉自https://www.cnblogs.com/liyongqiang-cc/p/18628407
該文章在 2025/1/16 11:02:11 編輯過