一、前言
1、最近一直在看專案效能優化方式,俗話說的好專案優化第一步那當然是新增快取,我們的專案之所以卡的和鬼一樣,要麼就是你的程式碼迴圈查詢資料庫(這個之前在我們的專案中經常出現,現在慢慢在修正)或者程式碼做了很多不該做的事情。這個時候就可以引入我們的快取了。(只要你的程式碼不是寫的特別差,比如之前實習的我)。
2、快取主要分為兩種 客戶端(瀏覽器快取)、服務端快取。當我們的資料不需要及時返回的時候,可以考慮將頁面快取到客戶的瀏覽器中進行儲存,在一定的時間內訪問直接讀取瀏覽器快取的資訊。我們通過設定HTTP的響應頭 Cache-Control 來完成頁面儲存到瀏覽器快取中如下所示:
二、客戶端(瀏覽器快取)
1、在老的版本的MVC裡面,有一種可以快取檢視的特性(OutputCache),可以保持同一個引數的請求,在N段時間內,直接從mvc的快取中讀取,不去走檢視的邏輯。
//老版本的.NET 做法 [OutputCache(Duration =20)]//設定過期時間為20秒 public ActionResult ExampleCacheAction() { var time=DateTime.Now.ToString("yyyy年MM月dd日 HH時mm分ss秒"); ViewBag.time= time; return View(); }
2、在.Net core 中就沒有(OutputCache)了,使用的是(ResponseCache)特性。官方文件上稱:響應快取可減少客戶端或代理對 web 伺服器的請求數。 響應快取還可減少量工作的 web 伺服器執行程式生成響應。 響應快取由標頭,指定你希望客戶端、 代理和快取響應的中介軟體如何控制。
/* Duration 代表快取持續時間(秒)至少1秒 VaryByHeader 設定vary 請求頭資訊使用vary頭有利於內容服務的動態多樣性。例如,使用Vary: User-Agent頭,快取伺服器需要通過UA判斷是否使用快取的頁面。 Location 快取位置 None 報頭設定為“no-cache”不使用快取 Client 只快取在客戶端。設定“Cache-control”標題為“private”。 Any 快取在代理和客戶端。設定“Cache-control”標題為“public”。 NoStore 快取中不得儲存任何關於客戶端請求和服務端響應的內容。每次由客戶端發起的請求都會下載完整的響應內容。如果設定為False Duration必須大於0 VaryByQueryKeys 可以按照相同頁面,不同的引數進行相應的儲存 CacheProfileName 設定快取配置檔案的值,可以通過設定不同的快取引數 */ [ResponseCache(Duration = 50, VaryByQueryKeys = new string[] { "q","name" })] public IActionResult Index(int q,string name) { return View(DateTime.Now); }
3、通過執行我們可以看到,瀏覽器多了一個cache-control:public,max-age=50 它的意思是public快取在代理和客戶端。max-age=50代表快取的時間50秒。
4、還有一種簡單粗暴的實現方式,因為我們知道新增了這個特性只是在響應請求頭中新增了一個cache-control:public,max-age=50,那麼我們可以也可以直接在請求響應中設定這個請求頭就完事了,效果都是一樣的。
public IActionResult Index() { //直接一,簡單粗暴,不要拼寫錯了就好~~ Response.Headers[Microsoft.Net.Http.Headers.HeaderNames.CacheControl] = "public, max-age=600"; //直接二,略微優雅點 //Response.GetTypedHeaders().CacheControl = new Microsoft.Net.Http.Headers.CacheControlHeaderValue() //{ // Public = true, // MaxAge = TimeSpan.FromSeconds(600) //}; return View(); }
5、有時候為了統一管理快取配置,我們可以將快取配置提前寫到配置中,使用名字進行呼叫。[ResponseCache(CacheProfileName ="test")],在Startup中注入檢視的時候寫入。
//設定一些快取策略 services.AddControllersWithViews(options => { options.CacheProfiles.Add("default", new CacheProfile { Duration = 60 }); options.CacheProfiles.Add("test", new CacheProfile { Duration = 30, Location=ResponseCacheLocation.Client }); });
6、[ResponseCache] 引數
-
- Duration 設定快取的儲存時間(以秒為單位)。設定“Cache-control”中的“max-age”。
- Location
- Any 快取在代理和客戶端。設定“Cache-control”標題為“public”。
- Client 只快取在客戶端。設定“Cache-control”標題為“private”。
- None 每次有請求發出時,快取會將請求發到伺服器 ,伺服器端會驗證請求中所描述的快取是否過期,若未過期(注:實際就是返回304),則快取才使用本地快取副本。 報頭設定為“no-cache”。
- NoStore 快取中不得儲存任何關於客戶端請求和服務端響應的內容。每次由客戶端發起的請求都會下載完整的響應內容。
- VaryByHeader 使用vary頭有利於內容服務的動態多樣性。例如,使用Vary: User-Agent頭,快取伺服器需要通過UA判斷是否使用快取的頁面。
- VaryByQueryKeys 可以按照相同頁面,不同的引數進行相應的儲存
- CacheProfileName 設定快取配置檔案的值,可以通過設定不同的快取引數
三、服務端快取
1、ResponseCache也可以設定服務端快取,將我們返回的資料儲存在服務端中在一定的時間內返回儲存的資料,這裡我先引入一個案例,有時候我們需要傳遞不同的引數進行快取。
案例:當我們訪問的資料帶分頁引數的時候我們怎麼做呢?VaryByQueryKeys前面我們講了這個,可以根據不同的引數進行快取,那麼我們現在使用看看 。
結果:當我們執行的時候,發現報錯了,報錯的意思大致是說我們沒有使用中介軟體,但是為什麼我這個快取要使用到中介軟體呢?其實是因為要區分,我們請求的引數,然後會將我們的資料進行快取起來,就是實現了服務端快取。這裡的我們就要使用微軟提供的中介軟體了。
2、我們主要是在Startup中注入services.AddResponseCaching();和app.UseResponseCaching();中介軟體。服務端快取可以快取頁面資料和API資料,同時如果我們服務端存在資料,也就是快取命中的情況下,會直接從快取中取,不會再進入我們的方法。
public void ConfigureServices(IServiceCollection services) { services.AddResponseCaching(options => { options.UseCaseSensitivePaths = false; options.MaximumBodySize = 1024; options.SizeLimit = 100 * 1024*1024; }); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { app.UseResponseCaching(); }
服務端快取配置如下,當我們配置新增了中介軟體和注入快取之後,就可以使用VaryByQueryKeys了。當我們訪問一次之後就會將結果快取到我們的客戶端快取中,和服務端快取各一份。當我們使用同一個瀏覽器訪問的時候訪問的就是客戶端快取資訊,當我們切換瀏覽器訪問的時候也不會請求我們的方法,會先進入到我們的中介軟體中檢視是否存在服務端快取,如果存在就是直接拿快取進行返回,如果沒有就會請求方法返回,然後再將結果進行快取。
屬性 |
描述 |
---|---|
MaximumBodySize |
響應正文的最大可快取大小(以位元組為單位)。 預設值為 64 * 1024 * 1024 (64 MB)。 |
SizeLimit |
響應快取中介軟體的大小限制(以位元組為單位)。 預設值為 100 * 1024 * 1024 (100 MB)。 |
UseCaseSensitivePaths |
確定是否將響應快取在區分大小寫的路徑上。 預設值是 false。 |
3、對於一些常年不變或比較少變的js,css等靜態檔案,也可以把它們快取起來,避免讓它們總是發起請求到伺服器,而且這些靜態檔案可以快取更長的時間!如果已經使用了CDN,這一小節的內容就可以暫且忽略掉了。。。對於靜態檔案,.NET Core有一個單獨的StaticFiles中介軟體,如果想要對它做一些處理,同樣需要在管道中進行註冊。UseStaticFiles
有幾個過載方法,這裡用的是帶StaticFileOptions引數的那個方法。因為StaticFileOptions裡面有一個OnPrepareResponse可以讓我們修改響應頭,以達到HTTP快取的效果。
app.UseStaticFiles(new StaticFileOptions { OnPrepareResponse = context => { context.Context.Response.GetTypedHeaders().CacheControl = new Microsoft.Net.Http.Headers.CacheControlHeaderValue { Public = true, //for 1 year MaxAge = System.TimeSpan.FromDays(365) }; } });
四、使用前置條件
- 請求必須導致伺服器響應,狀態程式碼為200(正常)。
- 請求方法必須為 GET 或 HEAD。
- 在 Startup.Configure中,響應快取中介軟體必須置於需要快取的中介軟體之前。
- Authorization 標頭不得存在。
- Cache-Control 標頭引數必須是有效的,並且響應必須標記為 “public” 且未標記為 “private”。
- 如果 Cache-Control 標頭不存在,則 Pragma: no-cache 標頭不得存在,因為 Cache-Control 標頭在存在時將覆蓋 Pragma 標頭。
- Set-Cookie 標頭不得存在。
- Vary 標頭引數必須有效且不等於 *。
- Content-Length 標頭值(如果已設定)必須與響應正文的大小匹配。
- 不使用 IHttpSendFileFeature。
- Expires 標頭和 max-age 和 s-maxage 快取指令指定的響應不能過時。
- 響應緩衝必須成功。 響應的大小必須小於配置的或預設 SizeLimit。 響應的正文大小必須小於配置的或預設的 MaximumBodySize。
- “請求” 或 “響應” 標頭欄位中不得存在 “no-store” 指令。