文章出處

先梳理三個概念:

  • OutputCache:頁面輸出緩存,一般 ASP.NET 應用程序會用到。
  • Last-Modified:Http 響應頭(Http Reponse Header),由服務器發給客戶端,格式為 Last-Modified:Tue, 24 Mar 2015 06:40:46 GMT
  • If-Modified-Since:Http 請求頭(Http Request Header),由客戶端發給服務器,格式為 If-Modified-Since:Tue, 24 Mar 2015 06:40:46 GMT

還有兩個 HTTP 狀態碼:

  • 200(成功):正常狀態,服務器已成功處理了請求,每次都有客戶端和服務端的交互。
  • 304(未修改):自從上次請求后,請求的網頁未修改過,服務器返回此響應時,不會返回網頁內容。如果網頁自請求者上次請求后再也沒有更改過,將服務器配置為返回此響應(If-Modified-Since HTTP),服務器可以告訴客戶端網頁沒有變更,進而節省帶寬和開銷。

如果我們的應用程序沒有進行任何的緩存處理,客戶端在每次瀏覽頁面的時候,Last-Modified 和 If-Modified-Since 的響應值都為 NULL,并且 HTTP 狀態碼為 200,這沒什么問題。我們下面要做的工作先使用 OutputCache 實現緩存,代碼很簡單:

public static int index = 0;

[OutputCache(Duration = 120)]
public ActionResult About()
{
      FileHelper.Write(@"C:\Users\xishuai\Desktop\test.txt", (index+1).ToString());
      ViewBag.Message = "Message:" + index++;
      return View();
}

第一次請求:

  • Status Code:200
  • Last-Modified:Tue, 24 Mar 2015 07:13:46 GMT
  • If-Modified-Since:NULL
  • test.txt:0
  • Message:0

第二次請求:

  • Status Code:304
  • Last-Modified:Tue, 24 Mar 2015 07:13:46 GMT
  • If-Modified-Since:Tue, 24 Mar 2015 07:13:46 GMT
  • test.txt:0
  • Message:0

第三次請求:

  • Status Code:304
  • Last-Modified:Tue, 24 Mar 2015 07:13:46 GMT
  • If-Modified-Since:Tue, 24 Mar 2015 07:13:46 GMT
  • test.txt:0
  • Message:0

Message 和 test.txt 里面的值一直為 0,Message 是為了測試頁面緩存有沒有生效,test.txt 是為了測試 About Action 有沒有執行,這兩個值的測試結果是我們想要的。另外,可以看到,第一次刷新的時候,Last-Modified 是有值的,而 If-Modified-Since 卻沒有值,這是因為 Last-Modified 是服務器發給客戶端,而 If-Modified-Since 的產生必須要要通過 Last-Modified,并且是由客戶端發給服務器,這個在第二次刷新的時候就可以看到,在頁面輸出緩存的 120 秒內,這兩個值會一直不變。

dudu 之前的兩篇博文:

出現的問題就是我們在第三次請求的時候,HTTP 狀態碼為 200,之前的解決方式是 Response.Cache.SetOmitVaryStar(true);,這個我在做測試的時候沒有遇到,使用的是 MVC 5.2.2,微軟應該是修復了。


上面是 ASP.NET 中使用 OutputCache 進行緩存的處理,我們一般也是這么用的,根據對 Last-Modified 和 If-Modified-Since 的理解,我們能不能使用它們,來實現 OutputCache 的一些效果呢?下面我們來嘗試下,簡單代碼:

public static int index = 0;

public ActionResult About()
{
    string dt = Request.Headers["If-Modified-Since"];
    DateTime isModifiedSince;
    if (!string.IsNullOrEmpty(dt))
    {
        if (DateTime.TryParse(dt, out isModifiedSince))
        {
            if (isModifiedSince.AddSeconds(120) < DateTime.Now)
            {
                Response.Cache.SetLastModified(DateTime.Now);
            }
        }
    }
    else
    {
        Response.Cache.SetLastModified(DateTime.Now);
    }

    FileHelper.Write(@"C:\Users\xishuai\Desktop\test.txt", (index+1).ToString());
    ViewBag.Message = "Message:" + index++;
    return View();
}

先說下上面代碼的意思,首先獲取請求頭中 If-Modified-Since 的值,如果沒有值的話,就通過 SetLastModified 設置響應頭中 Last-Modified 的值,如果有值的話,進行時間間隔判斷,如果在 120 秒之外,則更新 Last-Modified 的值,否則不更新,我們來看下測試結果。

第一次請求:

  • Status Code:200
  • Last-Modified:Tue, 24 Mar 2015 07:34:58 GMT
  • If-Modified-Since:NULL
  • test.txt:0
  • Message:0

第二次請求:

  • Status Code:200
  • Last-Modified:NULL
  • If-Modified-Since:Tue, 24 Mar 2015 07:35:46 GMT
  • test.txt:1
  • Message:1

第三次請求:

  • Status Code:200
  • Last-Modified:Tue, 24 Mar 2015 07:36:03 GMT
  • If-Modified-Since:NULL
  • test.txt:2
  • Message:2

這是什么情況?和 OutputCache 的效果也差太多了吧,總的來說,HTTP 的狀態碼一直為 200,test.txt 和 Message 的值一直在發生變化,也就是說“緩存”沒有一點效果,而 Last-Modified 和 If-Modified-Since 則更奇怪,一會有值,一會沒值。其實很正常,如果 HTTP 的狀態碼為 200,當一個請求發起的時候,首先設置 Last-Modified 的值,而 If-Modified-Since 則是在下個請求才能生效,因為生效了,所以第二次請求的時候,我們并沒有設置 Last-Modified 的值,所以第一次和第二次的請求結果就是上面所示,下面的請求就是重復第一次和第二次請求。

我們知道,Last-Modified 和 If-Modified-Since 的結果和 HTTP 的狀態碼有關,下面我們再來修改下代碼:

public static int index = 0;

public ActionResult About()
{
    string dt = Request.Headers["If-Modified-Since"];
    DateTime isModifiedSince;
    if (!string.IsNullOrEmpty(dt))
    {
        if (DateTime.TryParse(dt, out isModifiedSince))
        {
            if (isModifiedSince.AddSeconds(120) < DateTime.Now)
            {
                Response.Cache.SetLastModified(DateTime.Now);
                Response.StatusCode = 200;
            }
            else
            {
                Response.StatusCode = 304;
            }
        }
        else
        {
             Response.StatusCode = 304;
         }
    }
    else
    {
        Response.Cache.SetLastModified(DateTime.Now);
        Response.StatusCode = 200;
    }

    FileHelper.Write(@"C:\Users\xishuai\Desktop\test.txt", (index+1).ToString());
    ViewBag.Message = "Message:" + index++;
    return View();
}

你可以看到我們想要做的目的吧,就是手動設置 HTTP 狀態碼,我們來看下測試結果。

第一次請求:

  • Status Code:200
  • Last-Modified:Tue, 24 Mar 2015 07:49:07 GMT
  • If-Modified-Since:NULL
  • test.txt:0
  • Message:0

第二次請求:

  • Status Code:304
  • Last-Modified:NULL
  • If-Modified-Since:Tue, 24 Mar 2015 07:49:07 GMT
  • test.txt:1
  • Message:0

第三次請求:

  • Status Code:304
  • Last-Modified:NULL
  • If-Modified-Since:Tue, 24 Mar 2015 07:49:07 GMT
  • test.txt:2
  • Message:0

說實話,就差一點和 OutputCache 的效果一樣,那差的是什么呢?其實就是 test.txt 里的值,在使用 OutputCache 的時候,這里面的值是不變的,也就是說 About Action 沒有被執行,而我們上面測試顯示,About Action 是執行的,對于 Message 來說,瀏覽器顯示的是緩存后的值,我們可以得出這樣的結論:當使用 OutputCache 的時候,客戶端只是向服務器發起一個 Request,僅此而已,這個我們在 Application_BeginRequest 事件中監控到,其余的頁面顯示完全是客戶端緩存的結果,當然,前提方式緩存方式是客戶端。

還有一個有意思的地方是,在使用 OutputCache 的時候,除了第一次請求外,其他請求結果中,Last-Modified 和 If-Modified-Since 的值是不變的,根據上面測試的結果,我們可以得出,If-Modified-Since 是 Last-Modified 設置之后的結果,If-Modified-Since 可以一直不變,只要 HTTP 狀態碼為 304,并且我們沒有對 Last-Modified 進行設置。而在使用 OutputCache 的時候,除了 If-Modified-Since 的值一直沒變,Last-Modified 的也一直沒變,這個有點詭異,應該是把請求和響應頭中的值也進行了緩存。

參考資料:


文章列表




Avast logo

Avast 防毒軟體已檢查此封電子郵件的病毒。
www.avast.com


arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()