使用了AspNetCoreRateLimit三方库,starup.cs配置如下。
using AspNetCoreRateLimit;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.OpenApi.Models;namespace RateLimitDemo01
{public class Startup{public Startup(IConfiguration configuration){Configuration = configuration;}public IConfiguration Configuration { get; } public void ConfigureServices(IServiceCollection services){// needed to load configuration from appsettings.jsonservices.AddOptions();// needed to store rate limit counters and ip rulesservices.AddMemoryCache();//load general configuration from appsettings.jsonservices.Configure<IpRateLimitOptions>(Configuration.GetSection("IpRateLimiting"));//load ip rules from appsettings.jsonservices.Configure<IpRateLimitPolicies>(Configuration.GetSection("IpRateLimitPolicies"));// inject counter and rules storesservices.AddSingleton<IIpPolicyStore, MemoryCacheIpPolicyStore>();services.AddSingleton<IRateLimitCounterStore, MemoryCacheRateLimitCounterStore>();// the IHttpContextAccessor service is not registered by default.// the clientId/clientIp resolvers use it.services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();// configuration (resolvers, counter key builders)services.AddSingleton<IRateLimitConfiguration, RateLimitConfiguration>();services.AddControllers();services.AddSwaggerGen(c =>{c.SwaggerDoc("v1", new OpenApiInfo { Title = "RateLimitDemo01", Version = "v1" });});}public void Configure(IApplicationBuilder app, IWebHostEnvironment env){if (env.IsDevelopment()){app.UseDeveloperExceptionPage();app.UseSwagger();app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "RateLimitDemo01 v1"));}app.UseIpRateLimiting();app.UseHttpsRedirection();app.UseRouting();app.UseAuthorization();app.UseEndpoints(endpoints =>{endpoints.MapControllers();});}}
}
客户端用了五组请求:None白名单 ,无限制,WhiteIP1限流1秒2次请求 ,WhiteIP2限流,因为每秒一次请求,所以分在一分钟五次的限流组中,ClientID001允许的客户ID,ClientID002不允许的客户端ID。
using System;
using System.Net.Http;
using System.Threading.Tasks;
namespace RateLimitDemo01_Client
{class Program{static async Task Main(string[] args){Console.WriteLine("");Console.WriteLine("回车开始:");Console.ReadLine();var url = "https://localhost:5001";Console.WriteLine("---------None-------------");await None(url);Console.WriteLine("---------WhiteIP1-------------");await WhiteIP1(url);System.Threading.Thread.Sleep(2000);Console.WriteLine("---------WhiteIP2-------------");await WhiteIP2(url);Console.WriteLine("---------ClientID001-------------");await ClientID001(url);Console.WriteLine("---------ClientID002-------------");await ClientID002(url);Console.ReadLine();}static async Task None(string url){for (var i = 0; i < 5; i++){using (var client = new HttpClient()){client.BaseAddress = new Uri(url);//appsettings中配置,所以自由访问 "EndpointWhitelist": [ "get:/none", "*:/home/add" ],var request = new HttpRequestMessage(HttpMethod.Get, "/none");var response = await client.SendAsync(request);var content = await response.Content.ReadAsStringAsync();Console.WriteLine($"状态码:{response.StatusCode},{(int)response.StatusCode},返回值:" + content);}}}static async Task WhiteIP1(string url){for (var i = 0; i < 5; i++){using (var client = new HttpClient()){client.BaseAddress = new Uri(url);/*"GeneralRules": [{"Endpoint": "*","Period": "1s","Limit": 2}……*/var request = new HttpRequestMessage(HttpMethod.Get, "/whiteip1");var response = await client.SendAsync(request);var content = await response.Content.ReadAsStringAsync();Console.WriteLine($"状态码:{response.StatusCode},{(int)response.StatusCode},返回值:" + content);}}}static async Task WhiteIP2(string url){for (var i = 0; i < 5; i++){using (var client = new HttpClient()){client.BaseAddress = new Uri(url);/*"GeneralRules": [……{"Endpoint": "*","Period": "1m","Limit": 5}]*/System.Threading.Thread.Sleep(1000);var request = new HttpRequestMessage(HttpMethod.Get, "/whiteip2");var response = await client.SendAsync(request);var content = await response.Content.ReadAsStringAsync();Console.WriteLine($"状态码:{response.StatusCode},{(int)response.StatusCode},返回值:" + content);}}}static async Task ClientID001(string url){for (var i = 0; i < 5; i++){using (var client = new HttpClient()){client.BaseAddress = new Uri(url);var request = new HttpRequestMessage(HttpMethod.Get, "/clientid");request.Headers.Add("X-ClientId", "client_level_001");var response = await client.SendAsync(request);var content = await response.Content.ReadAsStringAsync();Console.WriteLine($"状态码:{response.StatusCode},{(int)response.StatusCode},返回值:" + content);}}}static async Task ClientID002(string url){for (var i = 0; i < 5; i++){using (var client = new HttpClient()){client.BaseAddress = new Uri(url);var request = new HttpRequestMessage(HttpMethod.Get, "/clientid");request.Headers.Add("X-ClientId", "client_level_002");var response = await client.SendAsync(request);var content = await response.Content.ReadAsStringAsync();Console.WriteLine($"状态码:{response.StatusCode},{(int)response.StatusCode},返回值:" + content);}}}}
}
web服务的appsettings.json配置如下:
{"Logging": {"LogLevel": {"Default": "Information","Microsoft": "Warning","Microsoft.Hosting.Lifetime": "Information"}},"AllowedHosts": "*","IpRateLimiting": {"EnableEndpointRateLimiting": false,"StackBlockedRequests": false,"RealIpHeader": "X-Real-IP","ClientIdHeader": "X-ClientId","HttpStatusCode": 429,"IpWhitelist": [ "127.0.0.1" ],"EndpointWhitelist": [ "get:/none", "*:/home/add" ],"ClientWhitelist": [ "client_level_001" ],"GeneralRules": [{"Endpoint": "*","Period": "1s","Limit": 2},{"Endpoint": "*","Period": "1m","Limit": 5}]},"IpRateLimitPolicies": {"IpRules": [{"Ip": "127.0.0.1","Rules": [{"Endpoint": "*","Period": "1s","Limit": 10},{"Endpoint": "*","Period": "15m","Limit": 200}]}]}
}
其中 EnableEndpointRateLimiting是全部请求累计还是每个API请求累计,StackBlockedRequests拒约的请求是否计入计数器中。
一场景
"IpRateLimiting": {"EnableEndpointRateLimiting": false,"StackBlockedRequests": false,……
结果
None是不受限流限制的,因为在白名称内。WhiteIP1是因为一秒只能有两次请求,所以剩下的三次拒绝了,WhiteIP2是等待了两秒杀后再次一秒一次请求,所以请求了三次,第四次出错了,是因为一分钟只能有五次请求。ClientID001是允许的客户端,五次全过,ClientID002是不允许的客户端,五次全部拒绝。
二场景
"IpRateLimiting": {"EnableEndpointRateLimiting": true,"StackBlockedRequests": false,……
当EnalbeEndopintRateLimiting为true时,第个url都是独立计算的,WhiteI2因为是新的请求,每秒一次,所以全部通过,ClientID002虽然ClientID不正确,但是一秒两次的限制生效了。
三场景
"IpRateLimiting": {"EnableEndpointRateLimiting": false,"StackBlockedRequests": true,……
StackBlockedRequests为true,拒绝的请也会算在计数中,所以超过了每分钟五次的限制,WhiteIP2会被拒绝,如果把每次钟改成六次,可以看一下效果。
四场景
"IpRateLimiting": {"EnableEndpointRateLimiting": true,"StackBlockedRequests": true,……
与场景二相同,每个api单独计数,失败的也算在内。