如何在 ASP.NET Core 中实现速率限制?

在 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)     {         // 获取客户端的唯一标识(例如 IP 地址)         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); // 每分钟最多 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); // 每分钟最多 10个请求      app.UseRouting();      app.UseEndpoints(endpoints =>                      {                          endpoints.MapControllers();                      }); } 

4. 总结

在 ASP.NET Core 中实现速率限制有多种方式:

  • 自定义中间件:适合简单的场景,但需要自己实现逻辑。
  • 第三方库:如 AspNetCoreRateLimit,提供了更强大的功能和灵活性。
  • 分布式缓存:如 Redis,适合分布式环境。

根据你的需求选择合适的方式,确保你的 API 能够有效防止滥用和过载。

发表评论

评论已关闭。

相关文章