透過 HTTP Cache 讓 CDN 快取特定檔案

這篇來講 HTTP 快取的作法,不論你是要調整檔案快取時間、決定要不要讓 CDN 快取,還是要隨時保持最新的檔案,都可以透過這些 Header 來調整。

還記得昨天提到 CloudFlare 的快取機制 中,只會看副檔名而不會去看 MIME Type 嗎?這個意思就是,如果你有一個 API 是 https://example.com/image/3 的話,只要不是 .jpg 結尾,CloudFlare 就不會快取了。但沒關係,我們依然可以透過調整 HTTP Header 來建議 CDN、瀏覽器要不要快取。

這篇中提到的 Header,依然是指 Response Header,一樣可以透過 DevTools 來觀察。

告訴瀏覽器、CDN 要快取多久

首先是透過 cache-control 這個 Header 決定了檔案要快取多久,CDN 能不能快取。通常會使用 max-age 來決定這個快取可以用多久。比方說如果有張圖片的 cache-control: max-age=30 代表這個快取最多用 30 秒,如果使用者在第一次取得這張圖片的 15 秒後又嘗試取得這張圖片,瀏覽器會因為知道這張還沒過期、還能用,所以不跟 Server 拿,直接使用本機的快取(HTTP 200)。

Client 經過 CDN 再到遠端 Server 拿,所以對 Client 來說它會存一份快取,CDN 也會存一份快取。如果 Client 快取失效(或是從來沒快取過)了會先跟 CDN 拿,直到 CDN 快取也沒了,才會跟 Server 拿。

如果不想讓 CDN 快取的話,可以加上 private 標籤,例如有張圖片是 cache-control: private, max-age=30 的話,那只有 Client 端會快取圖片,CDN 不會理你,例如在 CloudFlare 上,cf-cache-status 一定是 MISS

過期了還能用嗎?

如果快取已經過期的話,Client 就會嘗試再跟 Server 拿一份。但是並不是每次請求檔案 Server 就會傳一次完整檔案。

例如,Server 可能會在某張圖片加上 Last-modified: 2019-10-06 18:00:00,這樣在就算過期,Client 也會先檢查目前過期的圖片是否仍然新鮮,如果正確的話,Server 就會回傳 HTTP 304 Not Modifed,表示這張快取還可以繼續用。

缺點是 Server 如果打開這個檔案再存檔,Last-modified 值可能就會改變,另外一個做法是 Etag 欄位。有點像是去算這個檔案的 hash 值,比對如果 hash 值相同也回傳 HTTP 304 Not Modified,只有 Etag 值不一樣的時候,才會重新從 Server side 拿資料。

結語

這篇大概講了 Server 可以丟什麼 Header 去調整快取機制,並沒有太詳細的介紹這個東西是怎麼處理的;也沒有去提到 Client 端怎麼送 if-modified-since 之類的表頭。這篇先這樣,可以試著在 koa 的 ctx.request.headers 中加入不同的參數去調整快取看看。

本篇文章同步發表在 iT邦幫忙