天天看點

HTTP 緩存相關

HTTP 緩存相關

網絡中資料傳輸是很耗時的,資料要在漫長的路徑中奔波,用戶端在資料完整到達前隻能等待。如果能夠複用已經請求過的資源,勢必會讓整個頁面加載高效許多。這可以通過合理地設定伺服器的緩存,與浏覽器的緩存機制配合以達到最優。

緩存設定得當不但可減少使用者等待時間,提升體驗,還節省伺服器開銷省流量帶寬。

緩存的配置有兩種政策:

穩定的内容 + 長期緩存

經常變動的内容 + 使用前詢問

在知道檔案内容不太可能變化的情況下,可對該資源進行長期緩存。

Cache-Control: max-age=31536000

這種模式下浏覽器擷取資源流程如下:

頁面:請求資源 a.v1.js,b.v1.css。

緩存:本地沒有,向伺服器擷取。

伺服器:找到資源并傳回,同時告知浏覽器緩存該資源,比如,緩存一年。

頁面:一段時間後再次請求 a.v2.js,b.v1.css。

緩存:發現本地有對 b.v1.css 的緩存,直接使用,對于 a.v2.js 則詢問伺服器。

伺服器:找到資源并傳回 a.v2.js,同時告知浏覽器緩存該資源。

可以看到,這種模式下,我們更新的是檔案名,即資源的 URI 位址,而不是直接更新檔案内容。因為檔案被緩存後,如果檔案名沒變,浏覽器是不會重新去擷取的。

對于經常變動的資源,但位址又不能變,比如靜态部落格頁面,則不能像上面那樣緩存。這種情況下可設定緩存為 no-cache。

Cache-Control: no-cache

需要注意的是,緩存 Header 的值不能按照字面意思來解釋,需要去了解它,比如:

no-cache 并不是表示不要緩存,而是緩存該資源,但使用前先詢問伺服器該資源是否有更新,而 no-store 才表示完全不緩存。

must-revalidate 不是必需重新驗證資源有效性的意思,而是暗含了一個前提,就是資源如果還沒有超過設定的緩存時限 max-age 才重新驗證。

此模式下,伺服器可通過下發 ETag 或 Last-Modified 響應頭,浏覽器下次再請求時會查檢查已緩存的資源,并帶上相應的 If-None-Match 或 If-Modified-Since 請求頭,然後伺服器再決定是否傳回新的資源或告知浏覽器直接使用本地緩存。

使用 ETag 的場景示例:

浏覽器請求資源。

伺服器傳回資源,并且帶上 ETag (可以是 hash 或者其他能夠跟随資源内容而變的 id)。

過段時間,浏覽器再次請求該資源,通過設定 If-None-Match 請求頭帶上前面得到的 ETag。

伺服器将 ETag 與資源内容進行比較,發現資源沒有更新過,傳回 304 (not modified)告訴浏覽器資源沒有變化,可使用本地已經緩存的版本。

浏覽器得到 304 響應,直接使用本地緩存。

整個過程沒有對資源進行重複下載下傳。

ETag/Last-Modified 不可用的情況下,伺服器始終下發完整資源。

相比方式一,這種方式始終會和伺服器進行一次溝通。

max-age 的注意事項

對易變的内容設定 max-age 方式的緩存容易引起各資源不一緻的問題。


比如設定緩存為如下格式時,

Cache-Control: must-revalidate, max-age=600

對于緩存時間小于 10 分鐘的資源,浏覽器不會重新請求而是直接使用緩存。

假設一個場景,頁面 A 包含一個公共腳本 common.js 和頁面 A 的業務腳本 a.js。當頁面 A 首頁加載時,所有資源都正确緩存。

過了一段時間,切換到頁面 B,頁面 B 也包含公共腳本 common.js,同時有自己的業務腳本 b.js。

在請求頁面 B 之前,因為已經緩存過 common.js,是以會使用緩存,但這期間檔案有可能已經更新。此時浏覽器使用舊的 common.js 運作頁面 B 勢必會出問題。

是以,對于經常變動的内容設定 max-age 是不推薦的做法。

多數情況下針對上面的問題,一次強刷就解決了,這也是有 bug 時研發會給出的高頻回複。

參考内容

Caching best practices & max-age gotchas

HTTP Caching

原文位址

https://www.cnblogs.com/Wayou/p/http_cache_stuff.html

繼續閱讀