Net DB Web多級緩存的實現(xiàn)
1、客戶端緩存(瀏覽器緩存)
HTTP有一套控制緩存的協(xié)議-RFC7234,其中最重要的就是cache-control這個相應(yīng)報文頭,服務(wù)器返回時,如果Response帶上
cache-control:max-age=5 ?#表示允許瀏覽器緩存5秒(僅是允許,瀏覽器是否緩存還看瀏覽器本身機制是否要遵循這套緩存協(xié)議)
Net 封裝好了一個緩存特性,如:

? ?public class HomeController : ControllerBase ? ?{ ? ? ? ?[ResponseCache(Duration = 5)]//告訴瀏覽器可用緩存5秒,Duration必須定義,不然請求會報錯 ? ? ? ?[HttpGet("GetNowDateTime")] ? ? ? ?public string GetNowDateTime() ? ? ? ?{ ? ? ? ? ? ?return DateTime.Now.ToString(); ? ? ? ?} ? ?}

執(zhí)行多次請求

第一行為首次請求,Response Headers:

cache-control: public,max-age=5 ? #告訴瀏覽器進行緩存content-encoding: gzip content-type: text/plain; charset=utf-8date: Sun, 19 Mar 2023 07:17:50 GMT server: Microsoft-IIS/10.0vary: Accept-Encoding x-powered-by: ASP.NET

后續(xù)5s內(nèi)的請求,都會從緩存中取,Size=disk cache即為緩存,取到的返回值和首次請求一致,直到過了5s,再次向服務(wù)器發(fā)起請求。
PS:勾選 Disable cache,發(fā)出的請求頭 Request Headers會加上
cache-control: no-cache ?#不從緩存中取數(shù)
2、服務(wù)器端緩存
如果有大量客戶端訪問服務(wù)器獲取數(shù)據(jù),僅依靠客戶端緩存,還是會讓服務(wù)器多次運行接口程序
服務(wù)端緩存就是為了解決這個問題
.Net 添加服務(wù)器緩存中間件
//app.UseCors(); //跨域,如果有app.UseResponseCaching();//啟動服務(wù)器緩存,位置介于這兩中間件之間app.MapControllers();
UseResponseCaching中間件需要和ResponseCache特性配合使用
Api代碼仍為

? ?public class HomeController : ControllerBase ? ?{ ? ? ? ?[ResponseCache(Duration = 5)]//告訴瀏覽器可用緩存5秒 ? ? ? ?[HttpGet("GetNowDateTime")] ? ? ? ?public string GetNowDateTime() ? ? ? ?{ ? ? ? ? ? ?return DateTime.Now.ToString(); ? ? ? ?} ? ?}

打開兩個瀏覽器訪問嘗試,功能實現(xiàn)!!!
不過,這種服務(wù)器緩存方式十分雞肋,存在的限制太多:
a)無法解決惡意請求給服務(wù)器帶來的壓力(Request Header帶上了cache-control: no-cache,不僅瀏覽器不讀緩存,服務(wù)器也不讀) b)響應(yīng)碼=200的Get或者Head的響應(yīng)才會被緩存 c)報文頭帶有Authorization、Set-Cookie等響應(yīng),不會緩存
?3、內(nèi)存緩存
內(nèi)存緩存需要自身在代碼定義,僅針對業(yè)務(wù)層面的緩存,不受請求頭影響
添加內(nèi)存緩存服務(wù)
builder.Services.AddScoped<IDBHelper, SqlServerHelper>(); //db注入 builder.Services.AddMemoryCache();//內(nèi)存緩存
模擬SqlServerHelper類

namespace DIDemo.Services { ? ?public record Staff(int Id, string acc); ? ?public class SqlServerHelper : IDBHelper ? ?{ ? ? ? ?List<Staff> _staff_list = new List<Staff>(); ? ? ? ?public SqlServerHelper() { ? ? ? ? ? ?_staff_list.Add(new Staff(1,"tom")); ? ? ? ? ? ?_staff_list.Add(new Staff(2,"jerry")); ? ? ? ?}public Staff? GetStaff(int Id) ? ? ? ?{ ? ? ? ? ? ?return this._staff_list.Find(x => x.Id == Id); ? ? ? ?} ? ?} }

定義一個查詢員工的接口

using DIDemo.Services;using Microsoft.AspNetCore.Http;using Microsoft.AspNetCore.Mvc;using Microsoft.Extensions.Caching.Memory;namespace DIDemo.Controllers { ? ?[Route("api/[controller]")] ? ?[ApiController] ? ?public class HomeController : ControllerBase ? ?{ ? ? ? ?private readonly IDBHelper _db; ? ? ? ?private readonly IMemoryCache _menCache; ? ? ? ?public HomeController(IDBHelper db, IMemoryCache menCache) ? ? ? ?{ ? ? ? ? ? ?_db = db; ? ? ? ? ? ?_menCache = menCache; ? ? ? ?} ? ? ? ?[HttpGet("GetStaff")] ? ? ? ?public ?ActionResult<Staff> GetStaff(int Id) ? ? ? ?{ ? ? ? ? ? ?Console.WriteLine("begin"); ? ? ? ? ? ?//1、從緩存取數(shù)據(jù) ? 2、緩存取不到,從數(shù)據(jù)庫取,添加緩存 ? ? ? ? ? ?var items = ?_menCache.GetOrCreate<Staff>($"staff_{Id}", ?(e) => ? ? ? ? ? ?{ ? ? ? ? ? ? ? ?Console.WriteLine("緩存不存在,開始寫緩存"); ? ? ? ? ? ? ? ?e.AbsoluteExpirationRelativeToNow= TimeSpan.FromSeconds(15); //15s后過期 ? ? ? ? ? ? ? ?e.SlidingExpiration = TimeSpan.FromSeconds(5); //5s滑動過期:5s內(nèi)訪問過緩存,會重新開始計算5s ? ? ? ? ? ? ? ?return _db.GetStaff(Id); ? ? ? ? ? ?}); ? ? ? ? ? ?if (items == null) ? ? ? ? ? ?{ ? ? ? ? ? ? ? ?return NotFound($"員工ID={Id},不存在"); ? ? ? ? ? ?} ? ? ? ? ? ?return items; ? ? ? ?} ? ?} }

GetOrCreate,如果獲取不到,就通過委托,查詢數(shù)據(jù)庫并寫入緩存
AbsoluteExpirationRelativeToNow:固定的過期時間
SlidingExpiration:滑動過期時間
兩個時間可用單獨定義,也可以一起定義,其中一個過期即為過期,通常不單獨使用SlidingExpiration,可能造成緩存無限續(xù)命
4、分布式緩存
涉及微服務(wù),負載均衡,需要一個集中管理的緩存服務(wù),也就是我們的分布式緩存
老生常談的Redis,看看以前寫的文章吧!