AspNetCoreRateLimit應用於MVC項目求助 前言 之前發過一篇文章: .NET Core WebApi介面ip限流實踐 - 妙妙屋(zy) - 博客園 (cnblogs.com) 然後應用在前後端分離項目這個組件是非常好用的。但應用於不分離的項目,比如我的個人博客就有點麻煩。 就是我 ...
AspNetCoreRateLimit應用於MVC項目求助
前言
之前發過一篇文章:
.NET Core WebApi介面ip限流實踐 - 妙妙屋(zy) - 博客園 (cnblogs.com)
然後應用在前後端分離項目這個組件是非常好用的。但應用於不分離的項目,比如我的個人博客就有點麻煩。
就是我的需求是評論介面限流,然後觸發限流後要回到文章頁面告訴用戶你觸發了限流,但是,使用這個組件,他會將返回信息以頁面的形式返回給你,我並不知道該如何去讓他回到文章頁面,也是琢磨了很久,用中間件去實現了這個效果,但是感覺不是很理想,如果有大佬知道更好的辦法,可以私信或評論,感激不盡。
實現的效果圖
評論介面
文章介面
_messages.Warning
是博客開源作者封裝的提示信息組件,可以採用別的方式去提示,問題不大。這裡就是將從緩存中的提示信息提取出來,然後因為這裡用的是緩存,用session做的唯一值處理,所以用session去取出來,如果從緩存中查出來存在,則提示被限流。
代碼實現
原理就是把組件自帶的信息提示設置為空字元串,自己在中間件中去使用。
這是限流規則:
這裡參數就不做多的解釋,可以去看之前發佈的那篇文章。只要把Content設置為空字元串即可。
然後就開始去寫中間件去處理觸發了限流該怎麼做
需要註冊緩存服務
builder.Services.AddMemoryCache();
app.Use(async (context, next) =>
{
var cache = context.RequestServices.GetRequiredService<IMemoryCache>();
// 保存原始響應流
var originalBody = context.Response.Body;
// 創建一個新的響應流
using var responseBody = new MemoryStream();
context.Response.Body = responseBody;
// 載入當前用戶的 Session 對象
await context.Session.LoadAsync();
await next.Invoke();
if (context.Response.StatusCode == 429)
{
var referer = context.Request.Headers["Referer"].ToString();
// 從 Session 中獲取一個字元串值
var value = context.Session.GetString("key");
if (string.IsNullOrEmpty(value))
{
// 如果 Session 中沒有值,則設置一個字元串值
context.Session.SetString("key", "value");
}
var sessionId = context.Session.Id;
if (!cache.TryGetValue("Errors", out Dictionary<string, string> errors))
{
errors = new Dictionary<string, string>();
cache.Set("Errors", errors, TimeSpan.FromSeconds(10));
}
errors[sessionId] = "您的請求已被限流,請稍後再試。";
// 重置響應流位置
responseBody.Seek(0, SeekOrigin.Begin);
// 讀取響應內容
// var bodyText = new StreamReader(responseBody).ReadToEnd();
// 設置新的響應流
context.Response.Body = originalBody;
// 設置新的響應狀態碼
context.Response.StatusCode = 302;
context.Response.Headers["Location"] = referer;
}
else
{
// 將響應流寫回到原始響應流中
responseBody.Seek(0, SeekOrigin.Begin);
await responseBody.CopyToAsync(originalBody);
}
});
註意這個中間件處理要放在app.UseRateLimit();
前面。
結尾
AspNetCoreRateLimit原本就講限流的ip存放在redis當中了的,但是我就是查不出來,如果能用該組件自帶的方法查詢出來,就不需要再寫一個中間件,當429的時候再用緩存存一次會話了。
總之暫且先用這種辦法吧,如果有更好的方法可以評論喲~