底下網羅關於 HTTP Caching, HTTP Conditional Request 的 Headers,會在接下來的段落陸續介紹到
| Header Name | Header Type | Explain | 
|---|---|---|
| Cache-Control | Request/Response | |
| Expires | Response | ❌ HTTP/1.0 就有的,逐漸被 Cache-Control 取代 | 
| Last-Modified | Response | 📗 Last-Modified: Sat, 12 Jul 2025 07:20:17 GMT | 
| ETag | Response | |
| Vary | Response | 📗 Vary: Accept-Encoding, Origin會在第 30 篇文章介紹到 | 
| Pragma | Request/Response | ❌ Deprecated | 
| Age | Response | 📗 Age: 24 | 
| If-Range | Request | 📗 If-Range: Strong ETag📗 If-Range: Last-Modified✅ Must be use with Range Request Header | 
| If-Modified-Since | Request | 📗 If-Modified-Since: Last-Modified✅ Conditional Request,主要用來更新快取 | 
| If-None-Match | Request | 📗 If-None-Match: Strong ETag | Weak ETag👶 Weak Comparison✅ Conditional Request,主要用來更新快取✅ If-None-Match 的優先度 > If-Modified-Since | 
| If-Unmodified-Since | Request | 📗 If-Modified-Since: Last-Modified✅ Conditional Request,主要用來更新資源 | 
| If-Match | Request | 📗 If-Match: Strong ETag💪 Strong Comparison✅ Conditional Request,主要用來更新資源✅ If-Match 的優先度 > If-Unmodified-Since | 
ETag: W/"0-2jmj7l5rSw0yVb/vlWAYkK/YBwk" # Weak
ETag: "0-2jmj7l5rSw0yVb/vlWAYkK/YBwk" # Strong
看看 NodeJS etag 的實作,就是拿 lastModified 跟 檔案大小 去做 hash
function stattag(stat) {
  var mtime = stat.mtime.getTime().toString(16);
  var size = stat.size.toString(16);
  return '"' + size + "-" + mtime + '"';
}
看看 NodeJS etag 的實作,實作上也是非常樸實無華
function entitytag(entity) {
  if (entity.length === 0) {
    // fast-path empty
    return '"0-2jmj7l5rSw0yVb/vlWAYkK/YBwk"';
  }
  // compute hash of entity
  var hash = crypto
    .createHash("sha1")
    .update(entity, "utf8")
    .digest("base64")
    .substring(0, 27);
  // compute length of entity
  var len =
    typeof entity === "string"
      ? Buffer.byteLength(entity, "utf8")
      : entity.length;
  return '"' + len.toString(16) + "-" + hash + '"';
}
| Directive | Request | Response | 
|---|---|---|
| max-age | 📗 Cache-Control: max-age=600代表 Response 在生成後的 600 秒內都算 fresh | |
| s-maxage (shared-maxage) | - | 📗 Cache-Control: s-maxage=600同 max-age優先度 > max-age | 
| no-cache | 同 ➡️ | 可被 cache,但是每次都需跟 origin server 驗證 | 
| no-store | 同 ➡️ | 禁止任何形式的 cache | 
| must-revalidate | - | Cache-Control: max-age=600, must-revalidate600 秒內可以使用 cache,超過的話就必須重新驗證 | 
| proxy-revalidate | - | 同 must-revalidate,for shared caches only | 
| private | - | Response 只能被存在 private cache | 
| public | - | Response 可被存在 shared cache | 
| no-transform | 同 ➡️ | 禁止中間層把 response body 做轉換 | 
| immutable | - | response 在 fresh 期間不會異動 | 
| stale-while-revalidate | - | Cache-Control: max-age=600, stale-while-revalidate=300swr 套件的命名來源 | 
| must-understand | - | Cache-Control: must-understand, no-store必須了解 status code 的涵義,才可以 cache | 
| only-if-cached | client 只想拿 cache 的資料 | - | 
| stale-if-error | 主流瀏覽器不支援 | - | 
| max-stale | 主流瀏覽器不支援 | - | 
| min-fresh | 主流瀏覽器不支援 | - | 
隨便打開一個網頁,F12 > Network > Disable Cache 打勾,實際發送的是 Cache-Control: no-cache

取消勾選,再重整網頁,實際發送的是 Cache-Control: max-age=0

If-* 開頭的 Request HeadersIf-* 條件為 true,則執行對應的 HTTP Method 操作If-Range + Range 用來發起 Conditional Range Request,true 回傳對應的 Range,false 回傳整個 resourceIf-None-Match + If-Modified-Since 通常會一起使用,用來更新快取If-Match + If-Unmodified-Since 通常會一起使用,用來更新資源,若 If-* 條件為 false,則回傳 412 Precondition FailedHTTP Caching 跟 HTTP Conditional Requests 是兩個密不可分的概念。在第一個篇章,我們先有一個概觀,把這個主題會用到的 Headers 都介紹過一輪,接下來我們就會進到實作的環節~