HTTP頭資訊
首先我們從資源被請求時,請求行為和資源快取的不同來看下HTTP頭資訊的表現:
資源的首次請求:
頁面重新整理-資源快取未過期:
頁面重新整理-資源快取已過期-資源未變更:
頁面重新整理-資源快取已過期-資源已變更:
資源被再次請求時-快取未過期:
快取策略
當瀏覽器請求資原始檔時,預設會將源資檔案快取到本地以便重複使用,加快網頁的載入速度。
瀏覽器的資源快取分為 from disk cache
和 from memory cache
兩類。當首次訪問網頁時,資原始檔被快取在記憶體中,同時也會在本地磁碟中保留一份副本。當使用者重新整理頁面,如果快取的資源沒有過期,那麼直接從記憶體中讀取並載入。當使用者關閉頁面後,當前頁面快取在記憶體中的資源被清空。當使用者再一次訪問頁面時,如果資原始檔的快取沒有過期,那麼將從本地磁碟進行載入並再次快取到記憶體之中。
伺服器可以通過Response Headers使用 expires
和 cache-control
設定一個有效的過期時間,當瀏覽器再次請求資源時會判斷本地快取是否已過期:
- 如果沒有過期那麼直接從本地快取讀取,不會產生http請求,此為 強快取。
- 如果已過期,那麼瀏覽器將重新向伺服器請求資源,這一過程往往伴隨著 快取檢測。
expires
這是HTTP1.0版本的產物,屬於 Response Headers,使用一個UTC格式的日期時間字串表示資源的過期時間。
使用 expires
設定的過期時間是以伺服器時間為準的,它可能跟瀏覽器時間不一致,不同時區也會存在影響。
cache-control
這是HTTP1.1版本的產物,屬於 Response Headers,提供更多詳細的快取策略,可以根據三種不同性質通過逗號進行組合使用:
- 是否不使用快取:
cache-control: no-store/no-cache/must-revalidate
; - 是否為私有快取:
cache-control:public/private
; - 設定過期時間:
cache-control: max-age/s-maxage
;
是否不使用快取:
must-revalidate
: 當本地的資源快取沒有過期前,使用本地快取;當本地資源快取已過期時,需要進行快取檢測(預設值)。no-cache
: 不管本地的資源快取是否過期,都需要進行快取檢測。no-store
: 禁止瀏覽器快取資源,每次請求資源都去伺服器重新下載。
是否為私有快取:
public
: 公共快取,表示瀏覽器和代理伺服器都可以設定快取(預設值)。private
: 私有快取,僅瀏覽器設定快取。
設定過期時間:
max-age
:使用cache-control: max-age=60
的形式表示本地快取的資源將在xx秒之後過期,單位為秒,會覆蓋Expires
的設定。s-maxage
: 使用方式同max-age
,在public設定下有效,針對共享快取(代理伺服器)有效。
使用 max-age
的優點在於設定的過期時間是一個相對於瀏覽器的時間,不受伺服器和瀏覽器時間不一致的影響,也不會因為時區的不同而受到影響。
啟發式快取
當資原始檔的 Response Headers 中帶有 last-modified 欄位,但是卻缺少 expires
和 cache-control
用來表示資源快取的過期時間的欄位,這個時候瀏覽器會使用啟發式快取來確認該資源快取的過期時間:
瀏覽器會根據 date
和 last-modified
之間的時間差值的10%來作為資源快取的過期時間。
快取檢測
當瀏覽器重新向伺服器請求資源時,如果原先的 Response Headers 中存在 last-modified
或者 etag
資訊,那麼在 Request Headers 中會通過 if-modified-since
和 if-none-match
將之前的資訊帶給伺服器進行檢測。如果伺服器資源相對於本地的資源快取沒有發生變更,那麼將會返回304狀態碼,表示資源未更新,讓瀏覽器使用本地的資源快取,這就是 協商快取。
如果原先的 Response Headers 中沒有 last-modified
和 etag
資訊,那麼將從伺服器重新下載資原始檔。
last-modified 和 if-modified-since
這兩個欄位都是HTTP1.0版本的產物。
-
last-modified
: 屬於 Response Headers,表示資源最後一次修改的時間。 -
if-modified-since
: 屬於 Request Headers,用來判斷伺服器端資源是否在該傳遞的時間之後做了修改,如果沒有修改那麼伺服器將返回304狀態碼,讓瀏覽器使用資源快取。
etag 和 if-none-match
這是HTTP1.1版本的產物。
-
etag
: 屬於 Response Headers,表示資源的唯一識別符號,由伺服器端生成。 -
if-none-match
: 屬於 Request Headers,用來判斷伺服器資源是否與該傳遞的識別符號不一致,如果一致則表示資原始檔沒有修改過,伺服器將返回304狀態碼,讓瀏覽器使用資源快取。會覆蓋if-modified-since
的設定。
使用etag來判斷伺服器端資原始檔是否做了修改,主要有以下考慮:
last-modified
只能精確到秒,而有些伺服器資源可能在1秒內進行了多次修改。- 伺服器資原始檔,有些會定時自動生成,但是檔案內容並沒有發生任何變更。
使用者行為
瀏覽器的快取策略還跟使用者的行為有關:
- 當使用者從url位址列回車訪問網頁時,強快取和協商快取都有效。
- 當使用者從頁面中點選一個超連結訪問網頁時,強快取和協商快取都有效。
- 當使用者按F5重新整理時,強快取將無效,但會觸發協商快取。不過在Firefox瀏覽器中,強快取和協商快取均無效。
- 當使用者按Ctrl+F5強制重新整理時,強快取和協商快取都將無效,瀏覽器將向伺服器重新並下載資原始檔。
demo檢驗
為了徹底搞清楚瀏覽器的快取策略,這裡提供了一個使用node http模組構建的一個簡單伺服器環境,通過自行設定Response Headers來預覽瀏覽器快取的表現行為。點選下載資源包。
下載資源包後,自行解壓,然後使用 npm install
命令安裝依賴,通過 node server
執行目錄下的server.js檔案來啟動本地伺服器,將會自動使用預設瀏覽器開啟目錄下的 /pages/index/index.html
頁面。
之後可以在cache.json配置檔案的下圖所示的程式碼中,對瀏覽器快取涉及到的四個http欄位進行編輯,修改完畢後儲存並強制重新整理瀏覽器頁面即可:
編輯說明:
- 設定相關欄位為false,則表示不設定相應的http欄位;
- 對於Cache-Control欄位的值,填寫其支援的策略組合即可;
- 對於Expires欄位的值,按秒填寫數字即可;
- 對於Etag和Last-modified欄位的值,設定為true即可;