asp.net core服务中的限流

元气小坏坏 提交于 2021-01-25 17:24:36

使用了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.json
            services.AddOptions();
            // needed to store rate limit counters and ip rules
            services.AddMemoryCache();
            //load general configuration from appsettings.json
            services.Configure<IpRateLimitOptions>(Configuration.GetSection("IpRateLimiting"));
            //load ip rules from appsettings.json
            services.Configure<IpRateLimitPolicies>(Configuration.GetSection("IpRateLimitPolicies"));
            // inject counter and rules stores
            services.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单独计数,失败的也算在内。

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!