之前發過一篇文章:
.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的時候再用快取存一次對談了。
總之暫且先用這種辦法吧,如果有更好的方法可以評論喲~