API限流解决方案

引言

限流是对外Api服务在使用过程上常常会碰到的需求。html

对客户端的访问频率进行限制能够有效防止由于客户端使用脚本或其余破坏性的方式对服务正常运行形成影响的风险。git

限流有多种解决方式,最简单的方式莫过于针对Ip进行限制:只容许某一个Ip在规定的时间内访问屡次,ip访问记录能够保存在内存或者其余高速数据存储服务中。github

固然咱们在开发过种中确定不会什么轮子都本身造,既浪费时间,出错几率大,考虑不全面。因此选择一个合适的轮子是很是重要的,今天在这里向你们推荐一个ASP.NET Core速率限制的解决方案**AspNetCoreRateLimit **json

AspNetCoreRateLimit 介绍

AspNetCoreRateLimit是一个ASP.NET Core速率限制的解决方案,旨在控制客户端根据IP地址或客户端ID向Web API或MVC应用发出的请求的速率。AspNetCoreRateLimit包含一个IpRateLimitMiddlewareClientRateLimitMiddleware,每一个中间件能够根据不一样的场景配置限制容许IP或客户端,自定义这些限制策略,也能够将限制策略应用在每一个API URL或具体的HTTP Method上。api

Nuget包

Nuget包引用,截止文章使用时 AspNetCoreRateLimit版本号3.2.2。服务器

Install-Package AspNetCoreRateLimit

配置说明

通用Ip配置规则

IpRateLimiting

名称 类型 说明
EnableEndpointRateLimiting bool false 则全局将应用限制,而且仅应用具备做为端点的规则*。例如,若是您设置每秒5次调用的限制,则对任何端点的任何HTTP调用都将计入该限制<br/>true 则限制将应用于每一个端点,如{HTTP_Verb}{PATH}。例如,若是您为 *:/api/values客户端设置每秒5个呼叫的限制
StackBlockedRequests bool true 若是但愿被拒绝的API调用计入其余时间的显示(分钟,小时等)<br />false 拒绝的API调用不会添加到调用次数计数器上;如客户端每秒发出3个请求而且您设置了每秒一个调用的限制,则每分钟或天天计数器等其余限制将仅记录第一个调用,即成功的API调用
RealIpHeader string 服务器背后是一个反向代理,若是你的代理服务器使用不一样的页眉而后提取客户端IP X-Real-IP使用此选项来设置
ClientIdHeader string 取白名单的客户端ID。若是此标头中存在客户端ID而且与ClientWhitelist中指定的值匹配,则不该用速率限制。
HttpStatusCode string 限制状态码
IpWhitelist string IP白名单:支持Ip v4和v6
EndpointWhitelist string 端点白名单
ClientWhitelist string 白客户端白名单
GeneralRules json 通用规则
QuotaExceededResponse json 自定义返回的内容<br />"QuotaExceededResponse": {<br/> "Content": "{{"code":429,"msg":"访问过于频繁,请稍后重试","data":null}}",<br/> "ContentType": "application/json",<br/> "StatusCode": 200<br/>}

参考内容,下面的配置文件表明的含义是:IP限制适应于全部全局,规则为每5秒访问3次app

{
  "IpRateLimiting": {
    "EnableEndpointRateLimiting": false,
    "StackBlockedRequests": false,
    "RealIpHeader": "X-Real-IP",
    "ClientIdHeader": "X-ClientId",
    "HttpStatusCode": 429,
    ////IP白名单:支持Ip v4和v6 
    "IpWhitelist": [ "127.0.0.1" ],
    "GeneralRules": [
      {
        "Endpoint": "*",
        "Period": "5s",
        "Limit": 3
      }
    ]
  }
}

GeneralRules

名称 类型 说明
Endpoint string 端点路径
Period string 时间段,格式:{数字}{单位};可以使用单位:s, m, h, d
Limit string 调用限制

EndPoint测试

端点格式:{HTTP_Verb}:{PATH},您可使用asterix符号来定位任何HTTP谓词。ui

Periodthis

期间格式:{INT}{PERIOD_TYPE},您可使用如下期间类型之一:s, m, h, d

Limit

限制格式:{LONG}

配置规则参考

"GeneralRules": [
  //1秒钟只能访问2次
  {
    "Endpoint": "*",
    "Period": "1s",
    //限制
    "Limit": 2
  },
  //15分钟只能调用100次
  {
    "Endpoint": "*",
    "Period": "15m",
    "Limit": 100
  },
  //12H只能调用1000
  {
    "Endpoint": "*",
    "Period": "12h",
    "Limit": 1000
  },
  //7天只能调用10000次
  {
    "Endpoint": "*",
    "Period": "7d",
    "Limit": 10000
  },
  //对api/rateLimit/GetDateTime接口的规则为5秒钟最多访问3次
  {
    "Endpoint": "*:/api/rateLimit/GetDateTime",
    "Period": "5s",
    "Limit": 3
  }
]

特殊Ip限制规则

"IpRateLimitPolicies": {
  //ip规则
  "IpRules": [
    {
      //IP
      "Ip": "84.247.85.224",
      //规则内容
      "Rules": [
        //1s请求10次
        {"Endpoint": "*","Period": "1s","Limit": 10},
        //15分钟请求200次
        {"Endpoint": "*","Period": "15m","Limit": 200}
      ]
    },
    {
      //ip支持设置多个
      "Ip": "192.168.3.22/25",
      "Rules": [
        //1秒请求5次
        {"Endpoint": "*","Period": "1s","Limit": 5},
        //15分钟请求150次
        {"Endpoint": "*","Period": "15m","Limit": 150},
        //12小时请求500次
        {"Endpoint": "*","Period": "12h","Limit": 500}
      ]
    }
  ]
}

相信看完通用Ip配置规则的小伙伴看这一段配置应该没有什么压力了,我在此也就很少作解释了。

使用特殊Ip限制规则须要在ConfigureService中启用这一段代码

//加载ip限制定制策略,即针对某一个ip的特殊限制,可选择性注释
//services.Configure<IpRateLimitPolicies>(configuration.GetSection("IpRateLimitPolicies"));

编码使用

了解了基本规则后,咱们开始进行编码工做

一、注入服务

由于涉及的注入内容比较多,咱们使用一个扩展方法标识Ip限制服务须要注入的内容。

public static class RateLimitedConfigureService
{
    public static void RateLimitedConfig(this IServiceCollection services, IConfiguration configuration)
    {
        //Option模式配置
        services.AddOptions();
        //存储速率限制计算器和ip规则
        services.AddMemoryCache();
        //加载ip限制通用策略
        services.Configure<IpRateLimitOptions>(configuration.GetSection("IpRateLimiting"));
        //加载ip限制定制策略,即针对某一个ip的特殊限制,可选择性注释
        //services.Configure<IpRateLimitPolicies>(configuration.GetSection("IpRateLimitPolicies"));

        //注入计数器和规则存储
        services.AddSingleton<IIpPolicyStore, MemoryCacheIpPolicyStore>();
        services.AddSingleton<IRateLimitCounterStore, MemoryCacheRateLimitCounterStore>();

        //httpContext使用须要注入的服务
        services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
        //配置(解析器、计数器密钥生成器)
        services.AddSingleton<IRateLimitConfiguration, RateLimitConfiguration>();
    }
}

1.1 配置服务

public void ConfigureServices(IServiceCollection services)
{
    //Ip限制配置
    services.RateLimitedConfig(_configuration);

    services.AddControllers();
}

1.2 启用管道

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
    app.UseDeveloperExceptionPage();
    }

    app.UseRouting();

    //管道事件启用客户端IP限制速率
    app.UseIpRateLimiting();
}

二、编写Api

/// <summary>
/// 流量限制使用说明
/// </summary>
[Route("api/rateLimit")]
[ApiController]
public class RateLimitController: Controller
{
    [HttpGet("GetDateTime")]
    public string GetDateTime()
    {
        return DateTime.Now.ToString("d");
    }
}

三、测试

正常请求

调用 http://localhost:5000/api/ratelimit/getdatetime请求接口,返回当前日期。

经过F12查看ResponseHeaders咱们能够发现多了三个参数,分别表明的含义为

X-Rate-Limit-Limit 限制时间区间

X-Rate-Limit-Remaining 剩余请求次数

X-Rate-Limit-Reset 请求重置时间

image-20210512155552048

每调用一次X-Rate-Limit-Remaining减去1,当没有请求次数能够调用时返回错误。

API calls quota exceeded! maximum admitted 3 per 5s.

错误请求

当请求数在时间界限外时页面返回错误信息。返回内容也能够自定义,请参考配置规则

参考

Asp.NET Core 限流控制-AspNetCoreRateLimit

.Net Core结合AspNetCoreRateLimit实现限流

相关文章
相关标签/搜索