在 ASP.NET Core 中实现限流(Rate Limiting):保护服务免受滥用与攻击
这里写目录标题
- 引言
- 一、方案一:ASP.NET Core 内置限流(.NET 7+)
- 1. 安装与配置
- 2. 应用限流策略
- 3. 策略类型与适用场景
- 二、方案二:第三方库 `AspNetCoreRateLimit`
- 1. 安装与配置
- 2. 配置文件示例(appsettings.json)
- 3. 高级功能
- 三、关键注意事项
- 四、总结
引言
在现代 Web 开发中,API 的高并发访问可能导致资源耗尽或服务崩溃,尤其在面对恶意攻击(如 DoS)时,限流(Rate Limiting)是保护服务的核心策略。ASP.NET Core 提供了多种限流方案,既支持内置中间件(.NET 7+),也可通过第三方库实现更复杂的场景。本文将详细介绍两种主流实现方案,并分析不同限流策略的适用场景。
一、方案一:ASP.NET Core 内置限流(.NET 7+)
从 .NET 7 开始,ASP.NET Core 原生集成了限流中间件 Microsoft.AspNetCore.RateLimiting
,支持固定窗口、滑动窗口和令牌桶等策略。
1. 安装与配置
首先安装 NuGet 包:
dotnet add package Microsoft.AspNetCore.RateLimiting
在 Program.cs
中配置限流服务:
using Microsoft.AspNetCore.RateLimiting;
using System.Threading.RateLimiting;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRateLimiter(options =>
{
// 示例:固定窗口策略(每分钟允许100次请求)
options.AddFixedWindowLimiter("FixedPolicy", opt =>
{
opt.PermitLimit = 100; // 时间窗口内允许的请求数
opt.Window = TimeSpan.FromMinutes(1);
opt.QueueProcessingOrder = QueueProcessingOrder.OldestFirst; // 处理队列顺序
opt.QueueLimit = 10; // 允许排队的请求数
});
// 其他策略(滑动窗口、令牌桶等)
options.AddSlidingWindowLimiter("SlidingPolicy", ...);
options.AddTokenBucketLimiter("TokenPolicy", ...);
// 全局拒绝响应配置
options.OnRejected = (context, _) =>
{
context.HttpContext.Response.StatusCode = 429;
return ValueTask.CompletedTask;
};
});
var app = builder.Build();
app.UseRateLimiter(); // 启用限流中间件(需在 UseRouting 之后)
2. 应用限流策略
- 全局限流:默认对所有端点生效。
- 端点级限流:通过
RequireRateLimiting
指定策略:
app.MapGet("/api/data", () => "Data").RequireRateLimiting("FixedPolicy");
3. 策略类型与适用场景
策略 | 原理 | 适用场景 |
---|---|---|
固定窗口 | 在固定时间窗口(如1分钟)内限制请求总数。 | 简单高频请求(如秒杀) |
滑动窗口 | 将窗口分为多个段,随时间滑动更新计数,平滑流量。 | 需要更均匀限制的场景 |
令牌桶 | 按固定速率生成令牌,请求需消耗令牌,允许突发流量。 | 突发流量(如批量操作) |
并发控制 | 限制同时处理的请求数,超出则排队或拒绝。 | 资源密集型操作(如文件上传) |
二、方案二:第三方库 AspNetCoreRateLimit
若需要更细粒度的控制(如基于 IP、客户端 ID 或自定义规则),推荐使用 AspNetCoreRateLimit
。它支持从配置文件动态加载策略,并集成分布式缓存。
1. 安装与配置
安装 NuGet 包:
dotnet add package AspNetCoreRateLimit
配置服务与策略:
var builder = WebApplication.CreateBuilder(args);
// 加载配置文件中的策略
builder.Services.Configure<IpRateLimitOptions>(builder.Configuration.GetSection("IpRateLimiting"));
builder.Services.AddSingleton<IIpPolicyStore, MemoryCacheIpPolicyStore>();
builder.Services.AddSingleton<IRateLimitCounterStore, MemoryCacheRateLimitCounterStore>();
builder.Services.AddMemoryCache();
var app = builder.Build();
app.UseIpRateLimiting(); // 启用IP限流中间件
2. 配置文件示例(appsettings.json)
{
"IpRateLimiting": {
"EnableEndpointRateLimiting": true,
"GeneralRules": [
{
"Endpoint": "*", // 所有端点
"Period": "1m", // 时间窗口
"Limit": 100 // 允许的请求数
},
{
"Endpoint": "POST:/api/orders",
"Period": "10s",
"Limit": 5 // 针对特定接口严格限流
}
]
}
}
3. 高级功能
- 基于客户端标识:通过请求头(如
X-ClientId
)区分客户端。 - 动态策略调整:运行时更新策略,无需重启服务。
- 分布式缓存支持:结合 Redis 实现多节点一致性限流。
三、关键注意事项
-
中间件顺序
确保UseRateLimiter()
在UseRouting()
之后调用,否则策略可能不生效。 -
分布式环境
若服务部署在多节点,需使用分布式缓存(如 Redis)替代内存存储,避免单节点计数不准确:builder.Services.AddSingleton<IRateLimitCounterStore, DistributedCacheRateLimitCounterStore>();
-
测试与监控
- 使用 Postman 或
curl
发送高并发请求验证限流。 - 记录被拒绝的请求日志,分析策略合理性:
options.OnRejected = (context, _) => { logger.LogWarning($"请求被拒绝:{context.HttpContext.Request.Path}"); return ValueTask.CompletedTask; };
- 使用 Postman 或
-
灵活选择策略
- 固定窗口:简单但可能允许突发流量。
- 滑动窗口:平滑流量,适合均衡限制。
- 令牌桶:允许突发,适合秒杀类场景。
四、总结
ASP.NET Core 提供了从内置中间件到第三方库的多种限流方案:
- 内置方案:适合简单场景,无需额外依赖,支持主流限流算法。
- AspNetCoreRateLimit:适合复杂需求,支持动态配置、客户端级限流和分布式部署。
通过合理配置限流策略,可以有效防止服务过载,提升系统稳定性。建议结合监控日志持续优化阈值,确保用户体验与系统安全的平衡。