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實現限流

相關文章
相關標籤/搜索