1. 程式人生 > >status code: 200 OK (FROM CACHE) 與 304 NOT MODIFIED

status code: 200 OK (FROM CACHE) 與 304 NOT MODIFIED

前幾天同事給我演示304的時候,控制檯網路資訊都是200(from cache),下來我深入研究了一下:

1.200 OK (FROM CACHE) 與 304 NOT MODIFIED均使用本地快取資源。

2.200 OK (FROM CACHE)未進行http請求,304 NOT MODIFIED為傳送伺服器請求後得到的狀態碼。


目錄

本地快取階段 Expires/Cache-Control

協商快取階段 Last-Modified/ETag

快取失敗階段

總結


web 快取

在一個Web應用中,應用到快取的地方有很多,瀏覽器快取,頁面快取,伺服器快取,資料庫快取等。

快取的作用主要有:

  • 加快頁面開啟速度
  • 減少網路頻寬消耗
  • 降低伺服器壓力

快取行為主要由快取策略決定,而快取策略由內容擁有者設定。這些策略主要通過特定的HTTP頭部表達。即開放資源的伺服器根據自身快取策略定義相應的http頭部欄位,收到response的瀏覽器根據response.header中的特定欄位進行相應處理。

當一個使用者發起一個靜態資源請求的時候,瀏覽器會通過以下幾步來獲取資源:

  • 本地快取階段:先在本地查詢該資源,如果有發現該資源,而且該資源還沒有過期,就使用這一個資源,完全不會發送http請求到伺服器;
  • 協商快取階段:如果在本地快取找到對應的資源,但是不知道該資源是否過期或者已經過期,則發一個http請求到伺服器,然後伺服器判斷這個請求,如果請求的資源在伺服器上沒有改動過,則返回304,讓瀏覽器使用本地找到的那個資源;
  • 快取失敗階段:當伺服器發現請求的資源已經修改過,或者這是一個新的請求(在本來沒有找到資源),伺服器則返回該資源的資料,並且返回200, 當然這個是指找到資源的情況下,如果伺服器上沒有這個資源,則返回404。

本地快取階段 Expires/Cache-Control

Expires

 Expires 頭部欄位指定快取到期GMT的絕對時間。如果expires到期需要重新請求,在該日期前的所有對該資源的請求都會直接使用瀏覽器快取而不用向伺服器請求。

瀏覽器請求某網頁,開啟Chrome控制檯檢視某資源的Response Headers(需要選取可快取資源,可控制檯中ctrl+f

搜尋Expires):

      
  但是使用Expires存在伺服器端時間和瀏覽器時間不一致的問題。

Cache-Control

Cache-Control是http 1.1中為了彌補 Expires 缺陷新加入的。對已快取的內容進行控制, 允許源伺服器覆蓋一個響應預設的快取功能,簡單地說,該欄位用於控制瀏覽器在什麼情況下直接使用本地快取而不向伺服器傳送請求:

  • Cache-control: public表示快取的版本可以被代理伺服器或者其他中間伺服器識別。
  • Cache-control: private意味著這個檔案對不同的使用者是不同的。只有使用者自己的瀏覽器能夠進行快取,公共的代理伺服器不允許快取。
  • Cache-control: no-cache意味著檔案的內容不應當被快取。這在搜尋或者翻頁結果中非常有用,因為同樣的URL,對應的內容會發生變化。

其他相關控制欄位

  • max-age: 指定快取過期的相對時間秒數,max-ag=0或者是負值,瀏覽器會在對應的快取中把Expires設定為1970-01-01 08:00:00。
  • s-maxage: 類似於max-age,只用在共享快取上,比如proxy。
  • public: 通常情況下需要http身份驗證的情況,響應是不可cahce的,加上public可以使它被cache。
  • no-cache: 強制瀏覽器在使用cache拷貝之前先提交一個http請求到源伺服器進行確認。這對身份驗證來說是非常有用的,能比較好的遵守 (可以結合public進行考慮)。它對維持一個資源總是最新的也很有用,與此同時還不完全喪失cache帶來的好處),因為它在本地是有拷貝的,但是在用之前都進行了確認,這樣http請求並未減少,但可能會減少一個響應體。
  • no-store: 告訴瀏覽器在任何情況下都不要進行cache,不在本地保留拷貝。
  • must-revalidate: 強制瀏覽器嚴格遵守你設定的cache規則。
  • proxy-revalidate: 強制proxy嚴格遵守你設定的cache規則。
  • cache:使用本地快取,不發生請求。

示例:

快取過期的相對時間為300秒,若300s內再次需要頁面資源,不傳送http請求,直接呼叫本地資源。

Cache-control值為“no-cache”時,訪問此頁面不會在Internet臨時文章夾留下頁面備份

注意:cache-control max-age 和 s-maxage 將覆蓋 Expires 頭部。即以 max-age 為判斷。

 

此時狀態碼200 OK (from cache),  瀏覽器沒有跟伺服器確認,直接用了瀏覽器快取。


協商快取階段 Last-Modified/ETag

Last-Modified :

伺服器端當允許某資源使用快取時,需要設定response頭以下欄位:

            response.Clear();
            response.ClearContent();
            response.Headers["Last-Modified"] = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
            response.Headers["ETag"] = id;//這裡假設的是根據不同的id
            response.CacheControl = "private";

Last-Modified :伺服器端上次修改該檔案的時間。

ETag:ensure tag,這個下文再說。

瀏覽器請求某網頁,開啟Chrome控制檯檢視某資源的Response Headers(需要選取可快取資源,可控制檯中ctrl+f搜尋Last-Modified):

客戶端再次請求該資源的時候,發現自己快取中有該資源,那麼在請求中會包含If-Modified-Since ,這個If-Modified-Since 的值就是快取檔案的 Last Modified

再次請求該資源時request headers中有If-Modified-Since欄位:

注:同一檔案response的Last-Modified與再次request該資源的If-Modified-Since值相同,此處不同因為我擷取報文的資源不同。

伺服器端根據請求的request.headers中相應欄位的值,判斷瀏覽器端上送的If-Modified-Since與伺服器端該資源的Last-Modified 是否相等,是則返回304,讓瀏覽器使用快取資源,否則返回status 200,重新發送該資源並返回新的資源最後修改時間Last-Modified

判斷是否返回資源,伺服器端程式碼示意:

var request = context.Request;
            var response = context.Response;
            if (request.Headers["If-Modified-Since"].NotNullOrEmpty() || request.Headers["If-None-Match"].NotNullOrEmpty())
            {
                response.StatusCode = 304;
                return;
            }
//非304情況下的操作 略

這段程式碼其實不準確,判斷了request.Header存在If-Modified-Since或者If-None-Match即返回304,準確應該是判別If-Modified-SinceIf-None-Match均通過才返回304,否則重新獲取資源返回200(資源可獲取的情況下)。在返回 304 的時候已經做了一次資料庫查詢,但避免了接下來更多的資料庫查詢,並且沒有返回請求內容只返回一個 HTTP Header,從而降低頻寬的消耗。

我們可以看到這裡除了If-Modified-Since還判斷了If-None-Match,要了解什麼是If-None-Match,我們先介紹一下上文的E-tag。

E-tag

E-tagLast-Modified的補充

Last-Modified本身有缺點,以下情況Last-Modified不能完成我們的要求。

  • Last-Modified最小單位是秒,如果所請求資源在一秒內更改,則Last-Modified校驗失效。
  • 我們可能只更改了檔案最後編輯時間,並未改變檔案內容,即Last-Modified改變,但不希望重新獲取資源。
  • 某些伺服器不能精確的得到檔案的最後修改時間。

此時我們在http頭部補充E-tag欄位,可以將某個能用來表明檔案內容是否被更改的值(比如md5)來作為ETag,若伺服器在響應一個資源時添加了ETag,當下一次瀏覽器再一次向伺服器請求該資源時(前提是瀏覽器中上一次的資源被快取過了),會在請求header中包含If-None-Match欄位,值等於ETag

response.header:

可以看到請求中既有Etag也有Last-Modified

request.header:

此時狀態碼 304 Not Modified ,瀏覽器和伺服器多確認了一次快取有效性,再用的快取。


快取失敗階段

當伺服器發現請求的資源已經修改過,伺服器則返回請求資料,並且返回200狀態碼,如果伺服器上沒有相應資料,則返回404。


總結

為什麼有時候明明命中了快取,控制檯中Status顯示的不是 200 from cache ?是瀏覽器的原因:

  • 觸發 200 from cache:

    • 直接點選連結訪問

    • 輸入網址按回車訪問

    • 二維碼掃描

  • 觸發 304 Not Modified:

    • 重新整理頁面時觸發

    • 設定了長快取、但 Entity Tags 沒有移除時觸發

  • 適用火狐,Chrome親測輸入網址按回車或者重新整理頁面都觸發200 from cache,不知道原因

一般會設定長時間的快取,儘量命中快取,然後靠更新靜態檔案的版本號來使快取失效

流程圖如下:簡單講就是,200from cache未傳送請求,直接使用快取,304 not modify為傳送請求後確認快取可用。 

首次請求:


再次載入某資源:

200from cache應該在為 快取是否過期-否 分支

參考文章:

https://www.cnblogs.com/micro-chen/p/6547049.html

https://blog.csdn.net/huwei2003/article/details/70139062

https://blog.csdn.net/LeeSirbupt/article/details/54409931

https://blog.csdn.net/kikikind/article/details/6266101