底下網羅關於 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 都介紹過一輪,接下來我們就會進到實作的環節~