ASP. NET Core gives a detailed explanation of different types of users' current limiting

  • 2021-11-24 01:15:46
  • OfStack

Preface

The boss put forward a new demand. From a certain day, free users can only inquire 100 times a day, and charging users can only inquire 100W times.

This is a current limiting problem, and you are smart enough to think about how to do it: record the number of queries of users every 1 day, and then compare them with different numbers according to the current user type, and return an error if it exceeds the specified number.

Well, the principle is as simple as that. However, there are more issues to consider when writing:

What is the data structure of statistical data? Dictionary or line record? Where are the statistics recorded? Memory or MySQL or Redis? How to count distributed applications accurately. Distributed Lock or Queue or Transaction? How to withstand when the throughput is relatively large? Memory or Redis or database cluster? Do you want to keep these data for 1 straight? Automatically expired or regular cleaning? How do I return an error? Custom Error or HTTP Standard Error Code?

It is a bit troublesome to do these things by yourself. Here is a middleware of ASP. NET Core to meet this current limiting requirement: FireflySoft. RateLimit. AspNetCore. The steps are as follows:

1. Install the Nuget package

Has been released to nuget. org, there are many ways to install, choose their own favorite on the line.

Package Manager Command:


Install-Package FireflySoft.RateLimit.AspNetCore

Or. NET command:


dotnet add package FireflySoft.RateLimit.AspNetCore

Or add the project file directly:


<ItemGroup>
<PackageReference Include="FireflySoft.RateLimit.AspNetCore" Version="1.2.0" />
</ItemGroup>

2. Using middleware

Using middleware in Startup. Configure, the demo code is as follows (detailed below):


public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
 ...

 app.UseRateLimit(new RateLimitProcessor<HttpContext>.Builder()
  .WithAlgorithm(new FixedWindowAlgorithm<HttpContext>( new[] {
   new FixedWindowRateLimitRule<HttpContext>()
   {
    Id = "1",
    ExtractTarget = context =>
    {
     //  It is assumed here that the user Id Is from cookie If it is transmitted from the center, it needs to be obtained according to the actual situation 
     return context.Request.GetTypedHeaders().Get<string>("userId");
    },
    CheckRuleMatching = context =>
    {
     //  It is assumed here that the user type is derived from the cookie Passed from the user, it may actually need to be based on the user Id Go and inquire again 
     // 0 Free user  1 Charging user 
     int userType = context.Request.GetTypedHeaders().Get<int>("userType");
     if(userType==0){
      return true;
     }
     return false;
    },
    Name=" Free user current limiting rules ",
    LimitNumber=100,
    StatWindow=TimeSpan.FromDays(1)
   },
   new FixedWindowRateLimitRule<HttpContext>()
   {
    Id = "2",
    ExtractTarget = context =>
    {
     //  It is assumed here that the user Id Is from cookie If it is transmitted from the center, it needs to be obtained according to the actual situation 
     return context.Request.GetTypedHeaders().Get<string>("userId");
    },
    CheckRuleMatching = context =>
    {
     //  It is assumed here that the user type is derived from the cookie Passed from the user, it may actually need to be based on the user Id Go and inquire again 
     // 0 Free user  1 Charging user 
     int userType = context.Request.GetTypedHeaders().Get<int>("userType");
     if(userType==1){
      return true;
     }
     return false;
    },
    Name=" Current limiting rules for charging users ",
    LimitNumber=1000000,
    StatWindow=TimeSpan.FromDays(1)
   }
  }))
  .WithError(new Core.RateLimitError()
  {
   Code=429,
   Message = " The number of queries reached the maximum limit of the day "
  })
  //.WithStorage(new RedisStorage(StackExchange.Redis.ConnectionMultiplexer.Connect("localhost")))
  .Build());

 ...
}

To use this middleware, you need to build an instance of current limiting processor named RateLimitProcessor, specify the request type of current limiting processing HttpContext, and set three aspects of current limiting processing:

Algorithms and corresponding rules for current limiting

Current limiting algorithm, according to this demand, it is OK to use fixed window algorithm, also known as counter algorithm. This middleware also provides sliding window algorithm leaky bucket algorithm token bucket algorithm can be selected according to the needs.

Different current limiting algorithms have different types of current limiting rules. Here, fixed window current limiting rules are used. Two rules are defined for free users and charging users respectively. Pay attention to several parameters:

Id: In the current version, Id must be specified manually and cannot be duplicated. ExtractTarget: Pass a method to extract the current limiting target from the request, in this case the user Id. CheckRuleMatching passes a method to check whether the current rule applies to the current request, which is determined according to the user type. StatWindow is the size of the fixed window, which is a time span, and here it is a day. LimitNumber is the current limit value, which will trigger the current limit if the number of requests exceeds it during StatWindow time.

There are two interesting settings here: ExtractTarget and CheckRuleMatching, which work together to allow users to customize their own current limiting goals and conditions completely freely, whether it is IP, ClientId or Url.

Persistence mode of current limiting statistical data

At present, the current limit count in FireflySoft. RateLimit can be saved in memory or Redis, or a new memory can be defined by implementing IRateLimitStorage, which defaults to memory storage when not set.

For programs that only need to deploy 1 copy, memory is enough in most cases; However, if the time window of current limiting is relatively long, such as limiting 300 times per hour, the count will be lost when restarting, which may be a risk, and it is more appropriate to use Redis at this time. For distributed applications, Redis storage is also recommended.

Current limiting statistics are automatically expired and removed according to the current limiting time window.

Error codes and messages when current is restricted

The default current limiting error Code is 429, which is returned as HttpStatusCode; Message defaults to null, and you can change it to any text prompt of your own, which will be returned as the content of Http Body.

The above is how to use FireflySoft. RateLimit. AspNetCore to distinguish and limit current for different types of users.

If you feel that the restriction is still a bit dead, such as returning an error message, and want to return an error message in json format, you can also use FireflySoft. RateLimit. Core to encapsulate your own ASP. NET Core middleware.

If you want to modify this program, you can use the project fork: https://github.com/bosima/FireflySoft.RateLimit

Summarize


Related articles: