ASP.NET Core中的Http缓存
ASP.NET Core中的Http緩存
Http響應(yīng)緩存可減少客戶端或代理對?web服務(wù)器發(fā)出的請求數(shù)。響應(yīng)緩存還減少了?web服務(wù)器生成響應(yīng)所需的工作量。響應(yīng)緩存由?Http請求中的?header控制。
而?ASP.NETCore對其都有相應(yīng)的實現(xiàn),并不需要了解里面的工作細(xì)節(jié),即可對其進(jìn)行良好的控制。
了解HTTP緩存
Http協(xié)議中定義了許多緩存,但總體可以分為強(qiáng)緩存和協(xié)商緩存兩類。
強(qiáng)緩存
強(qiáng)緩存是指緩存命中時,客戶端不會向服務(wù)器發(fā)請求,瀏覽器?F12能看到響應(yīng)狀態(tài)碼為?200,?size為?fromcache,它的實現(xiàn)有以下幾種方式:
Expires - 絕對時間
示例:?Expires:Thu,31Dec203723:59:59GMT,就表示緩存有效期至2037年12月31日,在這之前瀏覽器都不會向服務(wù)器發(fā)請求了(除非按?F5/?Ctrl+F5刷新)。
Cache-Control - 相對時間/更多控制
絕對時間是一個絕對時間,因為計算時不方便;而且服務(wù)端是依據(jù)服務(wù)器的時間來返回,但客戶端卻需要依據(jù)客戶的時間來判斷,因此也容易失去控制。
Cache-Control有以下選項(可以多選):
max-age: 指定一個時間長度,在這個時間段內(nèi)緩存是有效的,單位是秒(?s)。
例如設(shè)置?Cache-Control:max-age=31536000,也就是說緩存有效期為?31536000/24/60/60=365天。
s-maxage: 同?max-age,覆蓋?max-age、?Expires,但僅適用于共享緩存,在私有緩存中被忽略。
public: 表明響應(yīng)可以被任何對象(發(fā)送請求的客戶端、代理服務(wù)器等等)緩存。
private: 表明響應(yīng)只能被單個用戶(可能是操作系統(tǒng)用戶、瀏覽器用戶)緩存,是非共享的,不能被代理服務(wù)器緩存。
no-cache: 強(qiáng)制所有緩存了該響應(yīng)的用戶,在使用已緩存的數(shù)據(jù)前,發(fā)送帶驗證器的請求到服務(wù)器。(不是字面意思上的不緩存)
no-store: 禁止緩存,每次請求都要向服務(wù)器重新獲取數(shù)據(jù)。
must-revalidate: 指定如果頁面是過期的,則去服務(wù)器進(jìn)行獲取。(意思是瀏覽器在某些情況下,緩存失效后仍可使用老緩存,加了這個頭,失效后就必須驗證,并不是字面上有沒有過期都驗證)
其中最有意思的要數(shù)?no-cache和?must-revalidate了,因為它們的表現(xiàn)都不是字面意義。
no-cache并不是字面上的不緩存,而是會一直服務(wù)端驗證(真實意義很像字面上的?must-revalidate)。
而?must-revalidate是只是為了給瀏覽器強(qiáng)調(diào),緩存過期后,千萬要遵守約定重新驗證。
協(xié)商緩存
協(xié)商緩存是指緩存命中時,服務(wù)器返回?Http狀態(tài)碼為?304但無內(nèi)容(?Body),沒命中時返回?200有內(nèi)容。
在要精細(xì)控制時,協(xié)商緩存比強(qiáng)緩存更有用,它有?Last-Modified和?ETag兩種。
Last-Modified/If-Modify-Since(對比修改時間)
示例:
服務(wù)器:Last-Modified: Sat, 27 Jun 2015 16:48:38 GMT 客戶端:If-Modified-Since: Sat, 27 Jun 2015 16:48:38 GMTETag/If-None-Match(對比校驗碼)
服務(wù)器:ETag: W/"0a0b8e05663d11:0" 客戶端:If-None-Match: W/"0a0b8e05663d11:0"清緩存要點
按?F5刷新時,強(qiáng)緩存失效
按?Ctrl+F5刷新時 強(qiáng)緩存和協(xié)商緩存都失效
ASP.NET Core的Http緩存
ASP.NETCore中提供了?ResponseCacheAttribute來實現(xiàn)緩存,它的定義如下:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)] public class ResponseCacheAttribute : Attribute, IFilterFactory, IFilterMetadata, IOrderedFilter {public ResponseCacheAttribute();public string CacheProfileName { get; set; }public int Duration { get; set; }public bool IsReusable { get; }public ResponseCacheLocation Location { get; set; }public bool NoStore { get; set; }public int Order { get; set; }public string VaryByHeader { get; set; }public string[] VaryByQueryKeys { get; set; } }其中,?ResponseCacheLocation定義了緩存的位置,是重點:
// Determines the value for the "Cache-control" header in the response. public enum ResponseCacheLocation {// Cached in both proxies and client. Sets "Cache-control" header to "public".Any = 0,// Cached only in the client. Sets "Cache-control" header to "private".Client = 1,// "Cache-control" and "Pragma" headers are set to "no-cache".None = 2 }注意看源文件中的注釋,?Any表示?Cache-Control:public,?Client表示?Cache-Control:private,?None表示?Cache-Control:no-cache。
注意?ResponseCacheLocation并沒有定義將緩存放到服務(wù)器的選項。
其中?Duration表示緩存時間,單位為秒,它將翻譯為?max-age。
另外可以通過?VaryByHeader和?VaryByQueryKeys來配置緩存要不要通過?header和?querystring來變化,其中?VaryByHeader是通過?Http協(xié)議中的?Vary頭來實現(xiàn)的,?VaryByQueryKeys必須通過?Middleware來實現(xiàn)。
不要誤會,所有?ResponseCacheAttribute的屬性配置都不會在服務(wù)端緩存你的響應(yīng)數(shù)據(jù)(雖然你可能有這種錯覺),它和輸出緩存不同,它沒有狀態(tài),只用來做客戶端強(qiáng)緩存。
如果不想緩存,則設(shè)置?NoStore=true,它會設(shè)置?cache-control:no-store,我們知道?no-store的真實意思是不緩存。一般還會同時設(shè)置?Location=ResponseCacheLocation.None,它會設(shè)置?cache-control:no-cache(真實意思是表示一定會驗證)。
注意單獨(dú)設(shè)置?Location=ResponseCacheLocation.None而不設(shè)置?NoStore并不會有任何效果。
示例1
這是一個很典型的使用示例:
public class HomeController : Controller {[ResponseCache(Duration = 3600, Location = ResponseCacheLocation.Client)]public IActionResult Data(){return Json(DateTime.Now);} }我定義了?3600秒的緩存,并且?cache-control應(yīng)該為?private,生成的?Http緩存頭可以通過如下?C#代碼來驗證:
using var http = new HttpClient(); var resp1 = await http.GetAsync("https://localhost:55555/home/data"); Console.WriteLine(resp1.Headers.CacheControl.ToString()); Console.WriteLine(await resp1.Content.ReadAsStringAsync());輸入結(jié)果如下:
max-age=3600, private "2020-03-07T21:35:01.5843686+08:00"另外,?ResponseCacheAttribute也可以定義在?Controller級別上,表示整個?Controller都受到緩存的影響。
CacheProfileName示例
另外,如果需要共用緩存配置,可以使用?CacheProfileName,將緩存提前定義好,之后直接傳入這個定義名即可使用:
.ConfigureServices(s => {s.AddControllers(o =>{o.CacheProfiles.Add("3500", new CacheProfile{Duration = 3500, Location = ResponseCacheLocation.Client,});}); });這樣我就定義了一個名為?3500的緩存,稍后在?Controller中我只需傳入?CacheProfileName=3500即可:
public class HomeController : Controller {[ResponseCache(CacheProfileName = "3500")]public IActionResult Data(){return Json(DateTime.Now);} }總結(jié)
Http緩存分為強(qiáng)緩存和協(xié)商緩存,?ASP.NETCore提供了便利的?ResponseCacheAttribute實現(xiàn)了強(qiáng)緩存,還能通過?Profile來批量配置多個緩存點。
但?ASP.NET MVC并沒有提供協(xié)商緩存實現(xiàn),因為這些多半和業(yè)務(wù)邏輯相關(guān),需要自己寫代碼。靜態(tài)文件是特例,?Microsoft.AspNetCore.StaticFiles中提供有,因為靜態(tài)文件的邏輯很清晰。
ASP.NET中的?OutputCacheAttribute在?ASP.NETCore中不復(fù)存在,取而代之的是?app/services.AddResponseCaching(),這些和?Http協(xié)議不相關(guān)。
有機(jī)會我會具體聊聊這些緩存。
喜歡的朋友請關(guān)注我的微信公眾號:【DotNet騷操作】
總結(jié)
以上是生活随笔為你收集整理的ASP.NET Core中的Http缓存的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 远程办公也可以很高效
- 下一篇: Istio 2020 年 Roadmap