HTTP協定之緩存
之前寫過一個篇 【HTTP協定詳解】 ,這次繼續介紹HTTP協定中的緩存機制。HTTP協定提供了非常強大的緩存機制, 了解這些緩存機制,對提高網站的性能非常有幫助。 本文介紹浏覽器和Web伺服器之間如何處理"浏覽器緩存",以及控制緩存的http header.
本文會使用Fiddler來檢視HTTP request和Response, 如果不熟悉這工具,可以先參考[Fiddler教程] 。在看本文的時候, 請務必打開Fiddler來實踐。
閱讀目錄
- 緩存的概念
- 緩存的好處
- Fiddler可以友善地檢視緩存的header
- 如何判斷緩存新鮮度
- 通過最後修改時間,判斷緩存新鮮度
- 與緩存相關的header
- ETag
- 浏覽器不使用緩存
- 直接使用緩存,不去伺服器端驗證
- 如何設定IE不使用緩存
- 公有緩存和私有緩存的差別
緩存這個東西真的是無處不在, 有浏覽器端的緩存, 有伺服器端的緩存,有代理伺服器的緩存, 有ASP.NET頁面緩存,對象緩存。 資料庫也有緩存, 等等。
http中具有緩存功能的是浏覽器緩存,以及緩存代理伺服器。
http緩存的是指:當Web請求抵達緩存時, 如果本地有“已緩存的”副本,就可以從本地儲存設備而不是從原始伺服器中提取這個文檔。
緩存的好處是顯而易見的, 好處有,
1. 減少了備援的資料傳輸,節省了網費。
2. 減少了伺服器的負擔, 大大提高了網站的性能
3. 加快了用戶端加載網頁的速度
Fiddler中把header都分門别類的放在一起,這樣友善檢視。

Web伺服器通過2種方式來判斷浏覽器緩存是否是最新的。
第一種, 浏覽器把緩存檔案的最後修改時間通過 header ”If-Modified-Since“來告訴Web伺服器。
第二種, 浏覽器把緩存檔案的ETag, 通過header "If-None-Match", 來告訴Web伺服器。
通過最後修改時間, 來判斷緩存新鮮度
1. 浏覽器用戶端想請求一個文檔, 首先檢查本地緩存,發現存在這個文檔的緩存, 擷取緩存中文檔的最後修改時間,通過: If-Modified-Since, 發送Request給Web伺服器。
2. Web伺服器收到Request,将伺服器的文檔修改時間(Last-Modified): 跟request header 中的,If-Modified-Since相比較, 如果時間是一樣的, 說明緩存還是最新的, Web伺服器将發送304 Not Modified給浏覽器用戶端, 告訴用戶端直接使用緩存裡的版本。如下圖。
3. 假如該文檔已經被更新了。Web伺服器将發送該文檔的最新版本給浏覽器用戶端, 如下圖。
執行個體: 打開Fiddler, 然後打開部落格園首頁。然後F5重新整理幾次浏覽器。 你會看到部落格園首頁也用了緩存。
與緩存有關的header
我們來看看每個header的具體含義。
Request
Cache-Control: max-age=0 | 以秒為機關 |
If-Modified-Since: Mon, 19 Nov 2012 08:38:01 GMT | 緩存檔案的最後修改時間。 |
If-None-Match: "0693f67a67cc1:0" | 緩存檔案的Etag值 |
Cache-Control: no-cache | 不使用緩存 |
Pragma: no-cache | |
Response
Cache-Control: public | 響應被緩存,并且在多使用者間共享, (公有緩存和私有緩存的差別,請看另一節) |
Cache-Control: private | 響應隻能作為私有緩存,不能在使用者之間共享 |
Cache-Control:no-cache | 提醒浏覽器要從伺服器提取文檔進行驗證 |
Cache-Control:no-store | 絕對禁止緩存(用于機密,敏感檔案) |
Cache-Control: max-age=60 | 60秒之後緩存過期(相對時間) |
Date: Mon, 19 Nov 2012 08:39:00 GMT | 目前response發送的時間 |
Expires: Mon, 19 Nov 2012 08:40:01 GMT | 緩存過期的時間(絕對時間) |
Last-Modified: Mon, 19 Nov 2012 08:38:01 GMT | 伺服器端檔案的最後修改時間 |
ETag: "20b1add7ec1cd1:0" | 伺服器端檔案的Etag值 |
如果同時存在cache-control和Expires怎麼辦呢?
浏覽器總是優先使用cache-control,如果沒有cache-control才考慮Expires
ETag是實體标簽(Entity Tag)的縮寫, 根據實體内容生成的一段hash字元串(類似于MD5或者SHA1之後的結果),可以辨別資源的狀态。 當資源發送改變時,ETag也随之發生變化。
ETag是Web服務端産生的,然後發給浏覽器用戶端。浏覽器用戶端是不用關心Etag是如何産生的。
為什麼使用ETag呢? 主要是為了解決Last-Modified 無法解決的一些問題。
1. 某些伺服器不能精确得到檔案的最後修改時間, 這樣就無法通過最後修改時間來判斷檔案是否更新了。
2. 某些檔案的修改非常頻繁,在秒以下的時間内進行修改. Last-Modified隻能精确到秒。
3. 一些檔案的最後修改時間改變了,但是内容并未改變。 我們不希望用戶端認為這個檔案修改了。
執行個體, 打開Fiddler, 打開部落格園首頁。 你可以看到很多圖檔,或者CSS檔案都是用了緩存。 這些都是通過比較ETag的值,來判斷檔案是否更新了。
CTRL+F5強制重新整理浏覽器,或者設定IE。 可以讓浏覽器不使用緩存。
1. 浏覽器發送Http request, 給Web 伺服器, header中帶有Cache-Control: no-cache. 明确告訴Web伺服器,用戶端不使用緩存。
2. Web伺服器将把最新的文檔發送給浏覽器用戶端.
執行個體:
打開Fiddler, 打開部落格園首頁, 然後按CTRL+F5強制重新整理浏覽器,你将看到
Pragma: no-cache的作用和Cache-Control: no-cache一模一樣。 都是不使用緩存。
Pragma: no-cache 是HTTP 1.0中定義的, 是以為了相容HTTP 1.0. 是以會同時使用Pragma: no-cache和Cache-Control: no-cache
直接使用緩存,不去伺服器驗證
按F5重新整理浏覽器和在位址欄裡輸入網址然後回車。 這兩個行為是不一樣的。
按F5重新整理浏覽器, 浏覽器會去Web伺服器驗證緩存。
如果是在位址欄輸入網址然後回車,浏覽器會"直接使用有效的緩存", 而不會發http request 去伺服器驗證緩存,這種情況叫做緩存命中,如下圖
執行個體: 比較第一次通路部落格園首頁和第二次部落格園首頁
1. 啟動Fiddler, 用firefox打開部落格園首頁, 發現有50多個session。
2. 按CTRL+X将Fiddler中的所有session删除。 關閉firefox,重新打開一個firefox,打開部落格園首頁。 發現隻有30多個session.
分析; 少了的session是因為firefox直接用了緩存,而沒有發http request。
打開IE。點選工具欄上的, 工具->Internet選項->正常->浏覽曆史記錄 設定. 選擇“從不”。然後儲存。
然後點選“删除” 把Internet臨時檔案都删掉 (IE緩存的檔案就是Internet臨時檔案)。