ASP.NET Core WebApi AspNetCoreRateLimit 限流中间件学习
AspNetCoreRateLimit介绍:
AspNetCoreRateLimit是ASP.NET核心速率限制框架,能够对WebApi,Mvc中控制限流,AspNetCoreRateLimit包包含IpRateLimit中间件和ClientRateLimit中间件,每个中间件都可以为不同的场景设置多个限,该框架的作者是stefanprodan,项目nuget地址是https://github.com/stefanprodan/AspNetCoreRateLimit。
对客户端IP限流控制。
首先nuget安装 Install-Package AspNetCoreRateLimit ,在Startup中Code以下代码,添加服务和注入,其中的配置是什么;注释都有了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1); //添加appsettings.json services.AddOptions(); //需要存储速率和ip规则 services.AddMemoryCache(); //加载appsettings.json中的配置项 ,下面三项是加载general,rules services.Configure<IpRateLimitOptions>(Configuration.GetSection( "IpRateLimiting" )); services.Configure<IpRateLimitPolicies>(Configuration.GetSection( "IpRateLimitPolicies" )); //注入计时器和规则 services.AddSingleton<IIpPolicyStore, MemoryCacheIpPolicyStore>(); services.AddSingleton<IRateLimitCounterStore, MemoryCacheRateLimitCounterStore>(); //添加框架服务 services.AddMvc(); } |
在Configure中配置RateLimit的启动
1 2 3 4 5 6 7 8 9 10 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env,ILoggerFactory loggerFactory) { loggerFactory.AddConsole(Configuration.GetSection( "Logging" )); loggerFactory.AddDebug(); app.UseIpRateLimiting(); if (env.IsDevelopment()) app.UseDeveloperExceptionPage(); app.UseMvc(); } |
我们还需要再appsettings.json中写入配置和规则:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | "IpRateLimiting" : { "EnableEndpointRateLimiting" : false , "StackBlockedRequests" : false , "RealIpHeader" : "X-Real-IP" , "ClientIdHeader" : "X-ClientId" , "HttpStatusCode" : 429, "IpWhitelist" : [ "127.0.0.1" , "::1/10" , "192.168.0.0/24" ], "EndpointWhitelist" : [ "get:/api/license" , "*:/api/status" ], "ClientWhitelist" : [ "dev-id-1" , "dev-id-2" ], "GeneralRules" : [ { "Endpoint" : "*" , "Period" : "1s" , "Limit" : 2 }, { "Endpoint" : "*" , "Period" : "15m" , "Limit" : 100 }, { "Endpoint" : "*" , "Period" : "12h" , "Limit" : 1000 }, { "Endpoint" : "*" , "Period" : "7d" , "Limit" : 10000 } ] } |
如果EnableEndpointRateLimiting设置为false,那么这些限制就全局使用,例如,如果设置每秒5次调用的限制,对任何端口的任何http调用都计入这个限制,反之,如果它是true,那么该限制将应用于{端口}{path}中的每个端点。
如果stackblockedrequest设置为false,则不会将拒绝调用添加到节流阀计数器,如果你要拒绝你必须设置为true;
ClientidHeader用于提取白清单的客户端id,如果客户端id在这个里面,就不会应用速率限制。
覆盖特定IP一般规则:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | "IpRateLimitPolicies" : { "IpRules" : [ { "Ip" : "84.247.85.224" , "Rules" : [ { "Endpoint" : "*" , "Period" : "1s" , "Limit" : 10 }, { "Endpoint" : "*" , "Period" : "15m" , "Limit" : 200 } ] }, { "Ip" : "192.168.3.22/25" , "Rules" : [ { "Endpoint" : "*" , "Period" : "1s" , "Limit" : 5 }, { "Endpoint" : "*" , "Period" : "15m" , "Limit" : 150 }, { "Endpoint" : "*" , "Period" : "12h" , "Limit" : 500 } ] } ] } |
IP字段支持IP v4和v6值,我们还需要去定义速率限制规则
规则由端点,期间和限制组成,示例(将所有的端点的速率限制每秒2次呼叫),那么定义如下:
{
"Endpoint": "*",
"Period": "1s",
"Limit": 2
}
如果在同一端点,例如get/values在一秒中你调用了3次,那么第三次将会被阻止;但是如果说你在同一秒内还调用了Put/values那么不会阻止,因为他们不是在同一端点之中。在期间(Period)中,还有单位 s m h 等.
有的时候我们对拦截有一定的自定义需求的时候,我们可以继承IpRateLimitMiddleware,如以下定义:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | public class CustomizationLimitMiddleware : IpRateLimitMiddleware { private readonly IpRateLimitOptions _options; private readonly IIpPolicyStore _ipPolicyStore; public CustomizationLimitMiddleware(RequestDelegate next, IOptions<IpRateLimitOptions> options, IRateLimitCounterStore counterStore, IIpPolicyStore policyStore, ILogger<IpRateLimitMiddleware> logger, IIpAddressParser ipParser = null ) : base (next, options, counterStore, policyStore, logger, ipParser) { _options = options.Value; _ipPolicyStore = policyStore; } public override ClientRequestIdentity SetIdentity(HttpContext httpContext) { var clientId = "anon" ; if (httpContext.Request.Headers.Keys.Contains(_options.ClientIdHeader, StringComparer.CurrentCultureIgnoreCase)) { clientId = httpContext.Request.Headers[_options.ClientIdHeader].First(); } return new ClientRequestIdentity { Path = httpContext.Request.Path.ToString().ToLowerInvariant(), HttpVerb = httpContext.Request.Method.ToLowerInvariant(), ClientId = clientId }; } } |
行为
当客户端进行HTTP调用时,IpRateLimitMiddleware执行以下操作:
- 从请求体中获取IP,客户端IP,Http信息,和一些URL,如果需要修改自己的提取逻辑,可以覆盖IpRateLimitMiddleware.SetIdentity。
- 在白名单中搜索IP,客户端ID和URL,如果有匹配则不执行任何操作
- 在IP规则中搜索匹配项,所有适用的规则按期间分组,对于每个期间使用最严格的规则
- 在匹配的一般规则中搜索,如果匹配的一般规则具有IP规则中不存在的定义时间段,则也使用此一般规则
- 对于每个匹配规则,速率限制计数器递增,如果计数器值大于规则限制,则请求被阻止
如果请求被阻止,则客户端会收到如下文本响应:
1 2 3 | Status Code: 429 Retry-After: 58 Content: API calls quota exceeded! maximum admitted 2 per 1m. |
如果请求没有得到速率限制,那么匹配规则中定义的最长周期用于组成X-Rate-Limit标头,这些标头将在响应中注入:
1 2 3 | X-Rate-Limit-Limit: the rate limit period (eg. 1m, 12h, 1d) X-Rate-Limit-Remaining: number of request remaining X-Rate-Limit-Reset: UTC date time (ISO 8601) when the limits resets |
默认情况下,组织了客户端的调用我们都会记录到日志中,那么我们可以使用Microsoft.Extensions.Logging.ILogger,这个就略过了。
我们有的时候需要添加ip规则或者更新速率,如一下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | public class IpRateLimitController : Controller { private readonly IpRateLimitOptions _options; private readonly IIpPolicyStore _ipPolicyStore; public IpRateLimitController(IOptions<IpRateLimitOptions> optionsAccessor, IIpPolicyStore ipPolicyStore) { _options = optionsAccessor.Value; _ipPolicyStore = ipPolicyStore; } [HttpGet] public IpRateLimitPolicies Get() { return _ipPolicyStore.Get(_options.IpPolicyPrefix); } [HttpPost] public void Post() { var pol = _ipPolicyStore.Get(_options.IpPolicyPrefix); //add pol.IpRules.Add( new IpRateLimitPolicy { Ip = "8.8.4.4" , Rules = new List<RateLimitRule>( new RateLimitRule[] { new RateLimitRule { Endpoint = "*:/api/testupdate" , Limit = 100, Period = "1d" } }) }); //update _ipPolicyStore.Set(_options.IpPolicyPrefix, pol); } } |
这样呢,你可以将ip限制的规则放到数据库中再推送到缓存中。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异