Sitemap
Hannah Lin

Love coding ❤

Follow publication

Http Cache 快取

9 min readOct 30, 2024

--

🔖 文章索引

1. 設定 HTTP caching
2. HTTP caching 過期後,如何知道檔案是否有更新 ?
3. Content-addressable storage 檔名控制

Browser Cache (又稱 HTTP Cache) 在效能優化上占了很重要一環,雖然設定不關前端的事?! (大部分都是後端在 Server 設定),但只要牽扯到 Client Side 就是跟前端有關了是吧 XD。所以到底什麼是 HTTP Cache ?

想像小明要看 “哈利波特神秘魔法石”、“Clean Code” 這兩本書,若每次都必須去圖書館看那很浪費時間,不如直接借回家隨時想看就看,這樣也節省了每次必須到圖書管的通勤時間。

這邊的小明也就是 Browser,圖書館是 Server ,書則是網路資源。當 Browser 向 Server request 資源時 (例如某張圖片或某個 JS file),若在第一次拿到時就把他先存起來,那下一次 Browser 需要同一張圖片時就可以直接在 Cache 拿,不需要實際發送請求到 Server。

設定 HTTP caching

最常見的有三種 Scenarios: 完全不要快取 no-store、每次都發 request 檢查確認用的是最新版 no-cache、以及時間未到不會向伺服器發送請求 max-age

Cache Missing 不要快取

no-store: 每次都發 request 去跟 Server 要資料

  1. Browser 發送一個 HTTP request 要一張圖 me.jpg
  2. Server 回傳 me.jpg 給 Browser
  3. Browser 再次一個 HTTP request 要同一張圖 me.jpg
  4. Server 回傳 me.jpg

這樣的好處是每次都可以拿到最新的圖片,但若發送 request 要 1 秒,response 3 秒,那五次就必須等 20 秒,相當耗時。

Stale 確保是最新版

no-cache: 雖然會 cache,不過每一次都還是會發 request 問 Server 內容有沒有更新 (revalidate) ,沒更新就用 cache 的

  1. Browser 發送一個 HTTP request 要一張圖 me.jpg
  2. Server 回傳 me.jpg 給 Browser
  3. Browser 將此圖片存在用戶端內。
  4. Browser 再次一個 HTTP request 要同一張圖 me.jpg
  5. Server 使用 ETag (搭配 If-None-Match) 查看圖片是否有更新,沒更新就回傳 304 叫 Browser 直接用 Cache 資料; 有更新就回傳新的 me.jpg

這樣的好處是確保每次都可以拿到最新的圖片,且省掉回傳時間,若發送 request 要 1 秒,response 3 秒,那五次就等約 8 秒,比 no-store 快多了。(當然這邊時間只是舉例,因為去查看有無更新也需要時間,但實際上還是會比回傳時間快上許多)

Valid 時間未到不會向伺服器發送請求

max-age: 若 cache 沒有過期甚至不需要發送 request,直接就拿 Cache 的資料; 若 cache 過期那接下來流程會像 no-cache

  1. Browser 發送一個 HTTP request 要一張圖 me.jpg
  2. Server 回傳 me.jpg 給 Browser,且在 Header 塞一個 Cache-Control:max-age=60Etag: abcde 欄位,標示這張圖片要緩存 60 秒,過期後再去 Server 重拿。
  3. Browser 看到回應有 Cache-Control欄位,就將此圖片存在用戶端內。
  4. Browser 再次發一個 HTTP request 要同一張圖 me.jpg

Cache 沒過期

  • 發現 Browser 已經有 Cache 了,所以連 request 都不需要發了就直接從本地端拿回傳。

Cache 過期 (時間過了 100 秒)

  • 發現 Cache 已到期,再請新發送請求,並且帶這從之前 etag 拿到的圖片指紋,發送給 Server。
  • Server 使用 ETag (搭配 If-None-Match) 查看圖片是否有更新,沒更新就回傳 304 叫 Browser 直接拿 Cache 資料; 有更新就回傳更新後的 me.jpg

這樣的好處是超快,若 Cache 沒過期那拿五次只需要 4 秒! (比前面的 20 秒跟 8 秒都快),若 assets 超多那使用者體驗也會差非常多。但強制 cache 也有一個問題,就是過期時間若沒設定好就無法拿到最新的資料 (不過這有其他解決方法之後會提)。

Stale While Revalidate 稍微忍受過期的 response

Cache-Control: max-age=1, stale-while-revalidate=59<秒數>

表示在這 1 秒內直接拿 Cache,1–60 秒內可以重複使用這個過期的內容,但同時從背景做 revalidate 的動作,下一次才會拿到新的。61 秒後會重種發送 request

HTTP Status Code

Server 回應有兩種

  • 304 (Not Modified): 通常發生在 server 檢查後向 Browser 表示可以繼續使用原本 cache
  • 200 (ok): 只能代表成功回應,不能代表是從 Server response 還是 browser cache 來,但從 browser cache 來的會附註 disk cache / memory cache

HTTP caching 過期後,如何知道檔案是否有更新 ?

上面有提到當 Cache 過期就會重新發送 request 給 Server,看檔案是否有更新(revalidation) ,那 Server 是如何判斷的呢?

通常有兩種方法,一種是看修改時間 Last-Modified ; 另一個更準確是看檔案內容是否有修改 ETag

修改時間

Last-Modified (搭配 If-Modified-Since)

// Server Responce
Last-Modified: 2017-01-01 13:00:00

Server 回傳 Response 時會加一個 Last-Modified Header,表示這個檔案上一次的更改時間,Browser 會把這個檔案存進快取並標記這個時間,下一次發 request 時就會以 If-Modified-Since 來跟 Server 要,若時間一樣表示檔案沒更新,Server 就會回一個Status code: 304 (Not Modified),代表可以繼續沿用快取的這份檔案; 若時間對不上代表檔案有更新那 Server 就回傳新檔案。

// Browser Request
GET /me.jpg
If-Modified-Since: 2017-01-01 13:00:00

但使用更改時間決定檔案變動不是 100% 準確,因為有可能檔案內容根本沒變但直接存擋,所以使用 ETag 會更為準確。

檔案內容更動與否

ETag (搭配 If-None-Match)

// Server Responce
Etag: abc

Server 回傳 Response 時會加一個 Etag Header,可以想成同樣檔案 Etag 就相同,更動過檔案 Etag 就會不同。Browser 會把這個檔案存進快取並標記Etag,下一次發 request 時就會以 If-None-Match 詢問 Server 要有沒有新檔案,有的話就回傳新的,沒有的話就只要回傳 304 就好了。

// Browser Request
GET /me.jpg
If-None-Match: abc

Content-addressable storage 檔名控制

Hash of the stored data as the identifier and the address

main.asfdfdf.js // version 1
main.fklflm.js // version 2

Cache-Control: max-age=31536000, immutable

要如何讓檔案不更改就不要發 request 只讀 Cache 就好了呢? no-cache 做不到因為他每次都要先發 request; max-age 也沒有辦法判斷檔案有沒有更新,所以有人就提出 Content-addressable storage 概念,其實跟 Etag 概念有點像,只是把 hash 實做在 index.html 裡。

<head>
<link rel='stylesheet' href='style-434hdjx.css'></link>
<script src='main-asfdfdf.js'></script>
</head>

index.html 是 no-cache,而其他 assets (css, js) 都設定快取一年 Cache-Control: max-age=31536000,所以每一次 request index 都會去檢查是否有更新,若看到 js 或 css 名稱變了就會重新下載,若沒有更動就沿用快取檔案,immutable 表示的是這個檔案不可能會改變 ,所以完全不需要 revalidate (etag)。

--

--

Hannah Lin
Hannah Lin

Written by Hannah Lin

A Front End Developer girl comes from Taiwan

No responses yet