十年河東,十年河西,莫欺少年窮
學無止境,精益求精
客戶端緩存請參考:https://www.cnblogs.com/catcher1994/p/responsecaching.html
接着Json web Token 中間件,今天寫了個簡單的限速中間件
json web token 中間件地址:https://www.cnblogs.com/chenwolong/p/16444022.html
所謂限速中間件,主要作用用於限制用戶頻繁訪問,防止多次高頻率請求造成服務器壓力大
下面演示一個每秒鐘同一個IP地址只能訪問一次帶有JWT授權的Action,一秒內多次訪問,直接返回 visits are too frequent
代碼如下:
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Logging; using Newtonsoft.Json; using swapCommon; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace swap.Middlewares { /// <summary> /// 限制用戶頻繁訪問帶有JwtToken授權 的 action中間件,一秒一次 /// </summary> public class LimitActionMiddlewares { private readonly RequestDelegate next; private readonly IHostingEnvironment environment; private readonly IMemoryCache memory; private int milliSeconds = 1000;//一秒 public LimitActionMiddlewares(RequestDelegate next, IHostingEnvironment environment , IMemoryCache memory) { this.next = next; this.environment = environment; this.memory = memory; } public async Task Invoke(HttpContext context) { //正式環境限速 if (environment.IsProduction()) { var ip = context.Connection.RemoteIpAddress.ToString(); string key = $"User_{ip}"; long? lastVisit = memory.Get<long?>(key); // if (context.Items["userdata"] == null) { await next.Invoke(context); } else { if (lastVisit == null || Environment.TickCount64 - lastVisit > milliSeconds) { memory.Set<long>(key, Environment.TickCount64, TimeSpan.FromSeconds(10));//避免長期不訪問的用戶佔用服務器資源 await next.Invoke(context); } else { await Response(context, 429, "visits are too frequent"); } } } else { await next.Invoke(context); } } private async Task Response(HttpContext httpContext, int statusCode, string message) { httpContext.Response.StatusCode = statusCode; httpContext.Response.ContentType = "application/json; charset=utf-8"; var result = CommonBaseResponse.SetResponse(false, message); await httpContext.Response.WriteAsync(JsonConvert.SerializeObject(result)); } } }
服務註冊時需引入緩存中間件
public void ConfigureServices(IServiceCollection services) { services.AddResponseCaching(); //其他代碼 }
引用中間件時
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } //注意中間件的引入順序,jwt在前,limitAction在後 app.UseMiddleware<JwtMiddlewares>(); app.UseMiddleware<LimitActionMiddlewares>(); app.UseMiddleware<ExceptionMiddlewares>(); }
注意中間件的引入順序,jwt在前,limitAction在後
代碼解讀
if(context.Items["userdata"] == null) { await next.Invoke(context); }
context.Items["userdata"] 是通過Jwt中間件進行賦值了,在一次請求中,它可以在各個中間件之間傳遞。
本中間件作用於需要JWT授權的Action訪問,因此需要上述 if 判斷
更深次的原因是:
由上圖可知,一次請求,每個中間件都會被執行兩次,兩次執行過程所用時間小於1秒,如果不加上述 if 判斷,在swagger初始化時,會報visits are too frequent 異常。
請求示例
@陳臥龍的博客