區分http請求狀態碼來理解緩存(協商緩存和強制緩存)

什麼是http緩存呢,當我們使用chrome瀏覽器,按F12打開控制台,在網絡請求中有時候看到狀態碼是200,有時候狀態碼是304,當我們去看這種請求的時候,我們會發現狀態碼為304的狀態結果是:Status Code: 304 Not Modified,而狀態碼為200的時候一般會有四種情況,一種是直接返回200,沒有任何其他的標誌,另一種是Status Code: 200 OK (from memory cache),還有一種是Status Code: 200 (from disk cache)。最後一種不是太常見,Status Code: 200 (from Service Worker).後面這三種狀態碼看到的效果是灰色的,其實從給出的信息也能看出來是從緩存中獲取上數據。下面我們來詳細介紹一下他們都分別是什麼時候出現的。

其實我們可以按狀態碼來區分其為兩大類,分別是協商緩存–304和強制緩存–200

協商緩存(304)

這種方式使用到了headers請求頭裡的兩個字段,Last-Modified & If-Modified-Since 。服務器通過響應頭Last-Modified告知瀏覽器,資源最後被修改的時間:

Last-Modified: Thu, 20 Jun 2019 15:58:05 GMT 

當再次請求該資源時,瀏覽器需要再次向服務器確認,資源是否過期,其中的憑證就是請求頭If-Modified-Since字段,值為上次請求中響應頭Last-Modified字段的值:

If-Modified-Since: Thu, 20 Jun 2019 15:58:05 GMT 

瀏覽器在發送請求的時候服務器會檢查請求頭request header裏面的If-modified-Since,如果最後修改時間相同則返回304,否則給返回頭(response header)添加last-Modified並且返回數據(response body)。

另外,瀏覽器在發送請求的時候服務器會檢查請求頭(request header)裏面的if-none-match的值與當前文件的內容通過hash算法(例如 nodejs: cryto.createHash(‘sha1’))生成的內容摘要字符對比,相同則直接返回304,否則給返回頭(response header)添加etag屬性為當前的內容摘要字符,並且返回內容。

綜上總結為:

  • 請求頭last-modified的日期與響應頭的last-modified一致
  • 請求頭if-none-match的hash與響應頭的etag一致
    這兩種情況會返回Status Code: 304

強制緩存(200(from …))

這裏我們使用到了Cache-Control和Expires這兩個字段來進行控制,Cache-Control裏面可以有多個屬性,可以組合設置,其屬性有如下幾種:

  • max-age=xxx,最大的有效時間 單位秒,是一個相對時間
  • must-revalidate,如果超過了max-age的時間,必須向服務器發送請求,驗證資源的有效性
  • no-cache,基本等價於max-age=0,由協商緩存來決定是否緩存資源
  • no-store,真正意義上的不緩存
  • public,代表 http 請求返回的內容所經過的任何路徑當中(包括中間一些http代理服務器以及發出請求的客戶端瀏覽器),都可以對返回內容進行緩存操作
  • private,代表只有發起請求的瀏覽器才可以進行緩存。默認值

比如我們設置

Catch-Control:public,max-age=360000 

我們在之前說了強制緩存有三種情況,上面說返回200有四種,第一種其實是不緩存,正常服務器返迴響應。

Service Worker

這個東西其實本質上時服務器和客戶端之間的代理服務器,一般我們在使用react開發的時候,會發現在根目錄出現了一個server-worker.js文件,這個東西就是和service Worker緩存相關的,他會根據網絡的狀態做出不同的緩存策略,有時候斷網了,之前訪問過的接口有可能依然會返回數據,其數據來源就是從其緩存中讀取。

memory cache

這個是將資源緩存在了內存中。事實上,所有的網絡請求都會被瀏覽器緩存到內存中,當然,內存容量有限,緩存不能無限存放在內存中,因此,註定是個短期緩存。而其控制權在於瀏覽器。

disk cache

與內存緩存相對的,這個是將資源緩存在硬盤中。雖然相比於內存,硬盤的讀取速度要慢很多,但總比沒有強。硬盤緩存的控制權在後端,通過什麼控制呢?通過HTTP響應頭控制,也就是我們在上面說到的catche-control和expires

Expires設置的過期時間是一個絕對的GMT時間,例如:Expires:Thu,20 Jun 2019 20:00:00 GMT; 他告訴瀏覽器緩存有效性持續到2019年6月20日為止,一直都使用緩存來處理。

Expires有一個非常大的缺陷,它使用一個固定的時間,要求服務器與客戶端的時鐘保持嚴格的同步,並且這一天到來后,服務器還得重新設定新的時間。

HTTP1.1引入了Cathe-Control,它使用max-age指定組件被緩存多久,從請求開始在max-age時間內瀏覽器使用緩存,之外的使用請求,這樣就可以消除Expires的限制,

如果對瀏覽器兼容性要求很高的話,可以兩個都使用。

其實在上面說到的Last-Modified對比最後修改時間與Expires一樣是有缺陷的,如果,資源的變化的時間間隔小於秒級,比如說是毫秒級的,或者說資源直接是動態生成的,那根據Last-Modified判斷,資源就是每時每刻都最新的,即被修改過!

所以,Etag & If-Node-Match 就是來解決這個問題的。
Etag字段的值為文件的特殊標識,一般都是hash生成的,服務器存儲着資源的Etag值。接下來的流程都與Lst-Modified & If-Modified-Since一致,只不過,比較的值從最後修改時間變成了Etag值。

Etag的優點在於,對於動態資源或者現在流行的Restful API返回的JSON數據,這些是沒有修改時間這一說法的,但是Http標準並沒有規定Etag值如何生成,因此我們通過代碼自己生成Etag值。當然,計算Etag值會消耗服務器性能。

Cache-Control+Last-Modified+ETag 的優先級會如何?

因為http1.1>http1.0,所以Cache-Control>Expires,ETag>Last-Modified。依照就近原則,先找本地緩存,沒有再向服務器發請求,所以Expires>Last-Modified,Cache-Control>ETag,

如果瀏覽器只支持http1.0,那麼瀏覽器只會攜帶Last-Modified發送給後台,
如果服務器只支持http1.0,那麼服務器會以Last-Modified為標準。
如果瀏覽器支持http1.1,那麼瀏覽器會攜帶Cache-Control+Last-Modified+ETag發送給後台,
如果服務器支持http1.1,那麼服務器會以Cache-Control+ETag為標準。

200狀態碼和304狀態碼何時出現

在沒有設置Cache-Contral的情況下,設置Last-Modified和ETag緩存,會出現200(from cache)和304 交替出現的情況。

設置Cache-Contral的情況下,過期刷新會出現304(如果有更新內容,則是200),之後再過期之前刷新都是200(from cache)。如果要確保要向服務端確認,可以將Cache-Contral的max-age設置為0。

通過下圖我們可以清晰的明白200和304

https://www.oecom.cn/http-header-control/

 

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※回頭車貨運收費標準

※產品缺大量曝光嗎?你需要的是一流包裝設計!

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※推薦評價好的iphone維修中心

※教你寫出一流的銷售文案?

台中搬家公司教你幾個打包小技巧,輕鬆整理裝箱!

台中搬家遵守搬運三大原則,讓您的家具不再被破壞!