在前面 HTTP 的歷史中,有提到在 HTTP/1.0 和 HTTP/1.1 時,有加入了些優化的機制,讓瀏覽器可以 cache 一些之前請求過的 API 資料,不用每次都跟 Server 要,我們今天就來詳細的介紹一下
HTTP cache 的流程大綱,大致以幾個部分組成:
在 HTTP/1.0 時,其實已經有 http cache 的機制,雖然設計上還不太完善,但是基本上流程跟上面相同,而有一些相對應的 HTTP/1.0 的 header 可以協助整個 cache 機制的運作,我們就分以下 2 個部分介紹:
在 HTTP/1.0 中,提供了 Expires
header,讓我們可以用絕對時間,例如
Expires: Fri, 13 Oct 2023 07:28:00 GMT
如果瀏覽器中,有紀錄上次此 http request Expires
的時間,且現在時間比 Expires
紀錄的時間早,那 Browser 就會直接幫我們去 Browser Cache 拿取上一次的資料,就可以快速取得資料
但如果沒有 Expires
的值,或者超過 Expires
的時間,我們就會嘗試去跟 Server 要資料
這裡 Expires
其實有個問題,因為 Expires
紀錄的是絕對時間,當我們把我們電腦或 Server 的時間做更改後,就會導致 Browser 判斷錯誤,導致沒有辦法取到正確的資料,這部分在 HTTP/1.1 的時候,利用新的細粒度更高的 Cache-Control
header 來控制,解決了這個問題,下面會再詳細說明
當 Expires
已經過期時,Browser 就會嘗試去跟 Server 拿資料,但同時也會去檢查上次 API 回傳時,如果有說明上一次跟新時間是什麼,也就是 Last-Modified
,就會同時在發 request 時,加入 If-Modified-Since: <Last-Modified value>
到 request 中,去跟 Server 做比對,看 Browser 中儲存的 Last-Modified
是不是跟 Server 的時間一樣,
Last-Modified: Fri, 13 Oct 2023 07:28:00 GMT
Last-Modified
日期在 Browser's Last-Modified
之後,那就表示我們應該要取得新的 Server 資料,同時把新的資料更新到 Browser cache 中Last-Modified
日期與 Browser's Last-Modified
在同一天,那 Server 就會回傳 304 Not Modified
,並且 Browser 可以沿用原本的 cache
在 HTTP/1.1 中,完善了很多對 cache 機制的控制,讓 cache 機制能如預期的進行,例如:
Cache-Control
:利用相對時間,讓 cache 的期限同步,例如利用 max-age: 86400
表示只會存在現在的時間 + 1 天,就不會有絕對時間不一樣造成的問題了,cache 會在預期的 X 天後結束ETag
:利用內文產生的 hash 值,可以比較 Browser cache 的內容和 Server 的內容有無差異,就可以精準的知道需不需要重取內容了
在有了 Cache-Control
的 header 後,我們可以對 Browser cache 儲存的時間有更高細粒度的控制,可填入的值有:
max-age
: cache 可停留的秒數public
: 此 cache 可以被儲存在任何地方,像是 Browser, CDN 等private
:只有目標 Browser 能儲存此 cacheno-store
:不要儲存 cacheno-cache
:每次都先去跟 server 驗證,如果 Server 回傳 304 Not Modified
,再去取得 Browser cache且 Cache-Control
和 Expires
同時存在的話,會以 Cache-Control
為主,覆蓋掉 Expires
的功能
這些值也可以組合在一起,範例如下
Cache-Control value | Explanation |
---|---|
max-age=86400 | response 可以被瀏覽器和中介緩存(例如 CDN)緩存最多1天(60秒 x 60分鐘 x 24小時) |
private, max-age=600 | response 可以被瀏覽器緩存最多10分鐘(60秒 x 10分鐘),但不能被中介緩存緩存 |
public, max-age=31536000 | response 可以被任何緩存(包括瀏覽器和中介緩存)儲存最多1年 |
no-store | 不允許緩存回應,每次請求都必須完整地重新獲取回應 |
比起在 HTTP/1.0 時,只能利用 Last-Modified
時間去比對資料是否有更新過,在 HTTP/1.1 中,我們可以利用 內文 產出的 hash 值,也就是 Etag
來比較 Browser cache 和 Server 的資料是否有異動,當 我們將 Etag
加入到 If-No-Match
的 header 中,發出 request 值
Etag
不相符,則重新取得 Server 資料,並把新的 Etag
覆寫到 Browser cache 中Etag
相符,則 Server 回傳 304 - Not Modified
,可以直接去跟 Browser cache 要資料
(圖片來源:https://web.dev/articles/http-cache#flowchart)
且 Etag
的優先度會高於 Last-Modified
,會優先以 Etag
比較
Expires
和 Last-Modified
可達到 cache 流程機制,但這些 header 設計上還有許多漏洞,容易 Server Client 不同步Cache-control
和 ETag
,有更高的細粒度可以控制 cache,使得 Server 和 Client 的 cache 行為一致