.NET Core ResponseCache【緩存篇(一)】


一、前言

  源碼

   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” 指令。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM