引言
限流是對外Api服務在使用過程上常常會碰到的需求。html
對客戶端的訪問頻率進行限制能夠有效防止由於客戶端使用腳本或其餘破壞性的方式對服務正常運行形成影響的風險。git
限流有多種解決方式,最簡單的方式莫過於針對Ip進行限制:只容許某一個Ip在規定的時間內訪問屢次,ip訪問記錄能夠保存在內存或者其餘高速數據存儲服務中。github
固然咱們在開發過種中確定不會什麼輪子都本身造,既浪費時間,出錯機率大,考慮不全面。因此選擇一個合適的輪子是很是重要的,今天在這裏向你們推薦一個ASP.NET Core速率限制的解決方案**AspNetCoreRateLimit **json
AspNetCoreRateLimit 介紹
AspNetCoreRateLimit是一個ASP.NET Core速率限制的解決方案,旨在控制客戶端根據IP地址或客戶端ID向Web API或MVC應用發出的請求的速率。AspNetCoreRateLimit包含一個IpRateLimitMiddleware和ClientRateLimitMiddleware,每一箇中間件能夠根據不一樣的場景配置限制容許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 請求重置時間
每調用一次X-Rate-Limit-Remaining
減去1,當沒有請求次數能夠調用時返回錯誤。
API calls quota exceeded! maximum admitted 3 per 5s.
錯誤請求
當請求數在時間界限外時頁面返回錯誤信息。返回內容也能夠自定義,請參考配置規則