你真的瞭解HTTP快取嗎
有時,HTTP中的快取可能會非常讓人頭疼。按照文件正確地使用 HTTP 並不是那麼困難,但事實上,不同的瀏覽器和 HTTP版本常常困擾著我們。而我們自己或是不必或是沒有時間去鑽研所有的邊緣的情況。
這裡總結的實用並速記的規則,希望對大家有所幫助
靜態資源
永遠不會修改的內容:JS 和 CSS 檔案,圖片,和任何型別的二進位制檔案都屬於這個類目。
永遠,我確實說的是永遠。為靜態資源指定版本號是很通用的做法。它們無論什麼時候改動了,它們的 URL 就改變了。
這裡是一些針對靜態資源的簡單的規則:
在檔案或者路徑中嵌入指紋。避免為指紋使用查詢字串。另外,確保生成的URL長度超過8個不同的字元。
使用這些 HTTP 頭:
Cache-Control: public, max-age=31536000 Expires: (一年後的今天) ETag: (基於內容生成) Last-Modified: (過去某個時間) Vary: Accept-Encoding
針對靜態資源的設定就是那麼簡單。
動態資源
針對應用程式私密性和新鮮度方面需求的不同,我們應該使用不同的快取控制設定。
對於非私密性和經常性變動的資源(想像一下股票資訊),我們應該使用下面這些:
Cache-Control: public, max-age=0 Expires: (當前時間) ETag: (基於內容生成) Last-Modified: (過去某個時間) Vary: Accept-Encoding
這些設定的效果是:這些資源可以被公開地(通過瀏覽器和代理伺服器)快取起來。每一次在瀏覽器使用這些資源之前,瀏覽器或者代理伺服器會檢查這些資源是否有更新的版本,如果有,就把它們下載下來。
這樣的設定需要注意,瀏覽器在重新檢查資源時效性方面有一定的靈活性。典型的是,當使用者點選了「返回/前進」按鈕時,瀏覽器不會重新檢查這些資原始檔,而是直接使用快取的版本。你如果需要更嚴格的控制,需要告知瀏覽器即使當使用者點選了「返回/前進」按鈕,也需要重新檢查這些資原始檔,那麼可以使用:
Cache-Control: public, no-cache, no-store
不是所有的動態資源都會馬上變成過時的資源。如果它們可以保持至少5分鐘的時效,可以使用:
Cache-Control: public, max-age=300
經過這樣的設定,瀏覽器只會在5分鐘之後才重新檢查。在這之前,快取的內容會被直接使用。如果在5分鐘後,這些過時的內容需要嚴格控制,你可以新增must-revalidate欄位:
Cache-Control: public, max-age=300, must-revalidate
對於私密或者針對使用者的內容,需要把 public 替換為 private 以避免內容被代理快取。
Cache-Control: private, …
Cache-Control 和 Expires
當同時使用 Cache-Control 和 Expires 時,Cache-Control 獲得優先權。
同時使用 Cache-Control 和 Expires 意味著得到更廣泛的支援(被不同的瀏覽器和版本)。當然,它們兩個應該被配置成相同的時效值,以避免引起困惑。
參考 Expires: vs. Cache-Control: max-age
ETag 和 Last-Modified
這兩個頭在瀏覽器對資源做重新檢查驗證的時候會使用到。大致來說,瀏覽器只是盲目地儲存這兩個來自於伺服器的頭的值,然後在需要檢查驗證的時候,瀏覽器根據請求條件,把這兩個指傳送給伺服器(分別通過 If-None-Match 和 If-Modified-Since)。
注意只有在資源過期的情況下,檢查驗證才會發生。
在有條件的請求下,If-None-Match 和 If-Modified-Since 頭的出現取決於伺服器。然而,由於是伺服器生成的 ETag 和(或) Last-Modified,所以實際上,這沒有什麼大問題。大多數的瀏覽器在可能的情況下都會把著兩者都傳送給伺服器。
參考 What takes precedence: the ETag or Last-Modified HTTP header?
一個通常的建議是:避免使用 ETag。這不是一個總是有用的建議。ETag 在判斷內容是否真的改動方面確實提供了更為精確的控制。針對生成的 ETag,預設的Apache方法需要把檔案的索引節(inode),大小(size)和最後修改時間作為輸入求值得到。這會導致在負載均衡的環境中,生成的 ETag 值變得毫無用處,因為每個伺服器都會針對相同的檔案生成一個不同的 Etag 值。這個可能就是唯一的問題導致很多人完全禁用 ETag,其實只要精確地針對一個匹配的檔案生成一個獨一無二的 ETag 值,就沒有必要禁用 ETag 了。
手動按下 Ctrl-R
當按下 Ctrl-R 時,瀏覽器會攜帶下面的請求,以檢查是否需要更新快取內容:
Cache-Control: max-age=0 If-None-Match: … If-Modifed-Since: …
注意這並不只是和原伺服器建立連線,其同樣適用於代理伺服器。本質上,它只是重新檢查驗證內容。如果伺服器迴應了一個304,瀏覽器將會使用快取的內容。
Vary: Accept-Encoding
這個頭對於一些人來說可能比較陌生。
當一個資源啟用了 gzip 壓縮,並且被代理伺服器快取,客戶端如果不支援 gzip 壓縮,那麼在這樣的情況下將會得到不正確的資料(也就是,壓縮過的資料)。這將會使代理伺服器快取兩個版本的資源:一個是壓縮過的,一個是沒壓縮過的。正確版本的資源將在請求頭髮送之後進行傳輸。
還有一個現實的原因:IE 瀏覽器不快取任何帶有 Vary 頭但值不為 Accept-Encoding 和 User-Agent 的資源。所以通過這種方式新增這個頭,才能確保這些資源在 IE 下被快取。
本文譯自 Bryan Tsai 的 《Http Caching》。
相關文章
- 你真的瞭解 OkHttp 快取控制嗎?HTTP快取
- TCP/IP、HTTP、socket 這些,你真的瞭解嗎?TCPHTTP
- ViewStub你真的瞭解嗎View
- 你真的瞭解mongoose嗎?Go
- 你真的瞭解 WebSocket 嗎?Web
- 你真的瞭解HTTP中GET與POST的區別嗎?HTTP
- JavaScript 你真的瞭解this指向嗎JavaScript
- 你真的瞭解前端路由嗎?前端路由
- 你真的瞭解RPC嗎?RPC
- 你真的瞭解URLEncode嗎?
- 你真的瞭解“密碼”嗎?密碼
- 你真的瞭解nosql世界嗎?SQL
- 你真的瞭解iOS怎麼取屬性的嗎?iOS
- 你真的瞭解深度學習嗎?深度學習
- 你真的瞭解 Cookie 和 Session 嗎?CookieSession
- 你真的瞭解 Cookie 和 Session 嗎CookieSession
- 你真的瞭解npm-scripts嗎?NPM
- 你真的瞭解 Session 和 Cookie 嗎?SessionCookie
- 你真的瞭解js運算子嗎JS
- HTTP快取瞭解一下HTTP快取
- 你真的瞭解 React 生命週期嗎React
- 你真的瞭解Event Loop(事件環)嗎?OOP事件
- AnyForWeb分享:畫素!你真的瞭解嗎?Web
- 你真的瞭解python嗎?這篇文章帶你快速瞭解!Python
- TCP|你真的懂 HTTP 嗎?TCPHTTP
- 你真的瞭解響應式佈局嗎?
- 注意!JS的結構你真的瞭解嗎?JS
- 你真的瞭解延時佇列嗎(一)佇列
- 靈魂拷問,你真的瞭解DNS嗎?DNS
- 【UI設計師】你真的瞭解色彩嗎?UI
- 你真的瞭解Android金鑰庫嗎?Android
- platform 模組 你真的瞭解你的計算機嗎?Platform計算機
- 騰訊面試,你真的懂HTTP嗎?面試HTTP
- 你真的對 Linux 中的 Inode 瞭解嗎?Linux
- 你真的瞭解 Unicode 和 UTF-8 嗎?Unicode
- Python讀寫檔案你真的瞭解嗎?Python
- 面試官:你真的瞭解Redis分散式鎖嗎?面試Redis分散式
- stl中的sort函式,你真的瞭解嗎函式