標籤:

這種情況下,304還是200更好?

有一類資源,因為幾乎永遠不可能改變,所以設置了緩存一年:

Cache-Control: max-age=31536000
ETag: "......"

在這一年中,如果沒有清除緩存,那麼此後訪問這個資源可以享受完全沒有網路通訊的優勢。

但是當一年到時,就會出現驗證請求(如果之前有設置 ETag 或 Last-Modified):

If-None-Match: W/"...(之前設置的ETag的值)..."

這個時候問題來了。如果我們選擇返回 304,並對這個304響應進行緩存一年的設置,那就意味著此後的一年中,每次瀏覽器訪問這個資源的時候,都會因為原來的200響應已經到期,於是嘗試發出請求,然後在本地得到了緩存後的304響應,然後才能使用這個資源。

不知道我描述得對不對。如果是這樣,那麼使用了304響應省了一次流量,但卻讓客戶端此後都要在本地請求兩次(雖然最終都沒有發出請求),而如果量比較大,不知道對前端的性能影響如何。如果有影響,這個時候應該違背常識地忽略If-None-Match,而直接重新發送200響應嗎?

——以下是官網文檔的內容,從中間開始就完全不知道在說什麼東西了……

304 Not Modified

如果客戶端發送了一個帶條件的 GET 請求且該請求已被允許,而文檔的內容(自上次訪問以來或者根據請求的條件)並沒有改變,則伺服器應當返回這個狀態碼。

304響應禁止包含消息體,因此始終以消息頭後的第一個空行結尾。

- 該響應必須包含以下的頭信息:

- Date,除非這個伺服器沒有時鐘。假如沒有時鐘的伺服器也遵守這些規則,那麼代理伺服器以及客戶端可以自行將 Date 欄位添加到接收到的響應頭中去(正如RFC 2068中規定的一樣),緩存機制將會正常工作。

- ETag 和/或 Content-Location,假如同樣的請求本應返回200響應。

- Expires, Cache-Control,和/或Vary,假如其值可能與之前相同變數的其他響應對應的值不同的話。

- 假如本響應請求使用了強緩存驗證,那麼本次響應不應該包含其他實體頭;否則(例如,某個帶條件的 GET 請求使用了弱緩存驗證),本次響應禁止包含其他實體頭;這避免了緩存了的實體內容和更新了的實體頭信息之間的不一致。

假如某個304響應指明了當前某個實體沒有緩存,那麼緩存系統必須忽視這個響應,並且重複發送不包含限制條件的請求。

假如接收到一個要求更新某個緩存條目的304響應,那麼緩存系統必須更新整個條目以反映所有在響應中被更新的欄位的值。


而如果量比較大,不知道對前端的性能影響如何。

你高估了查詢緩存的成本。


簡單的回答:304 更好。

之前專門研究過 Chrome 的緩存與 CDN 是如何配合的,雖然 CDN 服務端返回只是一個Content-Length長度為 0 的 304 請求,但是要注意的是瀏覽器在本地緩存(disk cache)的結果並不是這個空的 304 結果,而是將此前被緩存過的 200 請求響應(包括 HTTP 消息頭和文件的內容) merge 了 304 狀態的混合結果,所以在 Chrome 調試工具的 Network 列表中看到的是 200 狀態的請求,並且是 from disk cache,但是查看這個請求的詳情時,你會驚訝的發現 Response Headers 里 status 是 304,類似下面的結果

Network 列表(200,from cache)

Response Headers 詳情(注意 status: 304)

cache-control:public, max-age=31536000
content-encoding:gzip
content-length:47719
content-type:text/javascript; charset=UTF-8
date:Mon, 04 Sep 2017 21:26:12 GMT
expires:Tue, 04 Sep 2018 21:26:12 GMT
last-modified:Tue, 29 Aug 2017 02:34:27 GMT
status:304

由此可以猜想 Google Chrome 的緩存實現機制,當發現 304 後,只是將這個狀態疊加在原 先 200 響應中存儲在本地緩存里。

綜上所述,304 仍然是最佳方案,包括 Google、阿里雲等幾乎所有的 CDN 都是按照這個規矩返回的,所以你提到的:

「原來的200響應已經到期,於是嘗試發出請求,然後在本地得到了緩存後的304響應,然後才能使用這個資源」

這種情況不會發生。


響應304,客戶端的緩存的有效期會再往後增加一年。並不是每次用到這個資源都會請求一次。


推薦閱讀:

HTTP冪等性概念?
WebSocket 是什麼原理?為什麼可以實現持久連接?
關於ajax請求的安全,如何避免csrf類似的攻擊?
Aspera技術如何實現原來需要傳26小時的24GB文檔做到只需30秒?

TAG:HTTP |