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 的場景:
If-None-Match
整個過程沒有對資源進行重複下載。
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 時研發會給出的高頻回覆。