在 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;
- }
- }
复制代码 2. 使用第三方库实现速率限定
假如你不想自己实现速率限定逻辑,可以使用一些现成的第三方库,例如:
2.1 AspNetCoreRateLimit
AspNetCoreRateLimit 是一个流行的 ASP.NET Core 速率限定库,支持 IP 地点、客户端 ID 和端点级别的速率限定。
安装
通过 NuGet 安装:- public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
- {
- app.UseMiddleware<RateLimitingMiddleware>(10); // 每分钟最多 10个请求
- app.UseRouting();
- app.UseEndpoints(endpoints =>
- {
- endpoints.MapControllers();
- });
- }
复制代码 配置
在 Startup.cs 中配置速率限定:- dotnet add package AspNetCoreRateLimit
复制代码 配置文件
在 appsettings.json 中添加速率限定配置:- 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();
- });
- }
复制代码 3. 使用分布式缓存实现速率限定
假如你的应用是分布式的(例如部署在 Kubernetes 或多个服务器上),可以使用分布式缓存(如 Redis)来实现速率限定。
3.1 使用 Redis 实现速率限定
你可以使用 Redis 来存储每个客户端的请求计数。以下是一个简单的示例:- {
- "IpRateLimiting": {
- "EnableEndpointRateLimiting": true,
- "StackBlockedRequests": false,
- "RealIpHeader": "X-Real-IP",
- "ClientIdHeader": "X-ClientId",
- "GeneralRules": [
- {
- "Endpoint": "*",
- "Period": "1m",
- "Limit": 10
- }
- ]
- }
- }
复制代码 3.2 注册中间件
在 Startup.cs 中注册中间件:- 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);
- }
- }
- }
复制代码 4. 总结
在 ASP.NET Core 中实现速率限定有多种方式:
- 自定义中间件:得当简单的场景,但需要自己实现逻辑。
- 第三方库:如 AspNetCoreRateLimit,提供了更强大的功能和灵活性。
- 分布式缓存:如 Redis,得当分布式环境。
根据你的需求选择合适的方式,确保你的 API 可以大概有效防止滥用和过载。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |