Web快取是一種儲存Web資源副本並在下次請求時直接使用該副本的技術。
Web快取可以分為這幾種:瀏覽器快取、CDN快取、伺服器快取、資料庫資料快取 。因為可能會直接使用副本免於重新傳送請求或者僅僅確認資源沒變無需重新傳輸資源實體,Web快取可以減少延遲加快網頁開啟速度、重複利用資源減少網路頻寬消耗、降低請求次數或者減少傳輸內容從而減輕伺服器壓力。
這篇文章主要討論和前端密切相關的瀏覽器HTTP快取
機制。瀏覽器HTTP快取
可以分為強快取
和協商快取
。強快取
和協商快取
最大也是最根本的區別是:強快取命中的話不會發請求到伺服器(比如chrome中的200 from memory cache),協商快取一定會發請求到伺服器,通過資源的請求首部欄位驗證資源是否命中協商快取,如果協商快取命中,伺服器會將這個請求返回,但是不會返回這個資源的實體,而是通知客戶端可以從快取中載入這個資源(304 not modified)。簡略流程圖如下:
瀏覽器HTTP快取由HTTP報文的首部欄位決定
控制強快取的欄位按優先順序介紹
-
Pragma
Pragma
是HTTP/1.1之前版本遺留的通用首部欄位,僅作為於HTTP/1.0的向後相容而使用。雖然它是一個通用首部,但是它在響應報文中時的行為沒有規範,依賴於瀏覽器的實現。RFC中該欄位只有no-cache
一個可選值,會通知瀏覽器不直接使用快取,要求向伺服器發請求校驗新鮮度。因為它優先順序最高,當存在時一定不會命中強快取。 -
Cache-Control
Cache-Control
是一個通用首部欄位,也是HTTP/1.1控制瀏覽器快取的主流欄位。和瀏覽器快取相關的是如下幾個響應指令:
指令 | 引數 | 說明 |
---|---|---|
private | 無 | 表明響應只能被單個使用者快取,不能作為共享快取(即代理伺服器不能快取它) |
public | 可省略 | 表明響應可以被任何物件(包括:傳送請求的客戶端,代理伺服器,等等)快取 |
no-cache | 可省略 | 快取前必需確認其有效性 |
no-store | 無 | 不快取請求或響應的任何內容 |
max-age=[s] | 必需 | 響應的最大值 |
- max-age(單位為s)設定快取的存在時間,相對於傳送請求的時間。只有響應報文首部設定
Cache-Control
為非0的max-age
或者設定了大於請求日期的Expires
(下文會講)才有可能命中強快取。當滿足這個條件,同時響應報文首部中Cache-Control
不存在no-cache
、no-store
且請求報文首部不存在Pragma
欄位,才會真正命中強快取。以下所有圖片均為重新整理(command+R)的截圖。
- no-cache 表示請求必須先與伺服器確認快取的有效性,如果有效才能使用快取(
協商快取
),無論是響應報文首部還是請求報文首部出現這個欄位均一定不會命中強快取。Chrome硬性重新載入(Command+shift+R)會在請求的首部加上Pragma:no-cache
和Cache-Control:no-cache
。 - no-store 表示禁止瀏覽器以及所有中間快取儲存任何版本的返回響應,一定不會出現強快取和協商快取,適合個人隱私資料或者經濟類資料。
- public 表明響應可以被瀏覽器、CDN等等快取。
- private 響應只作為私有的快取,不能被CDN等快取。如果要求HTTP認證,響應會自動設定為
private
。
- Expires
Expires是一個響應首部欄位,它指定了一個日期/時間,在這個時間/日期之前,HTTP快取被認為是有效的。無效的日期比如0,表示這個資源已經過期了。如果同時設定了
Cache-Control
響應首部欄位的max-age
,則Expires
會被忽略。它也是HTTP/1.1之前版本遺留的通用首部欄位,僅作為於HTTP/1.0的向後相容而使用。
控制協商快取的欄位
- Last-Modified/If-Modified-Since
If-Modified-Since是一個請求首部欄位,並且只能用在GET或者HEAD請求中。
Last-Modified
是一個響應首部欄位,包含伺服器認定的資源作出修改的日期及時間。當帶著If-Modified-Since
頭訪問伺服器請求資源時,伺服器會檢查Last-Modified
,如果Last-Modified
的時間早於或等於If-Modified-Since
則會返回一個不帶主體的304
響應,否則將重新返回資源。
If-Modified-Since: , :: GMT Last-Modified: , :: GMT
- ETag/If-None-Match
ETag
是一個響應首部欄位,它是根據實體內容生成的一段hash字串,標識資源的狀態,由服務端產生。If-None-Match
是一個條件式的請求首部。如果請求資源時在請求首部加上這個欄位,值為之前伺服器端返回的資源上的ETag
,則當且僅當伺服器上沒有任何資源的ETag
屬性值與這個首部中列出的時候,伺服器才會返回帶有所請求資源實體的200響應,否則伺服器會返回不帶實體的304
響應。ETag
優先順序比Last-Modified
高,同時存在時會以ETag
為準。
If-None-Match: <etag_value> If-None-Match: <etag_value>, <etag_value>, … If-None-Match: *
ETag屬性之間的比較採用的是弱比較演算法,即兩個檔案除了每個位元都相同外,內容一致也可以認為是相同的。例如,如果兩個頁面僅僅在頁尾的生成時間有所不同,就可以認為二者是相同的。
因為ETag
的特性,所以相較於Last-Modified
有一些優勢:
1. 某些情況下伺服器無法獲取資源的最後修改時間
2. 資源的最後修改時間變了但是內容沒變,使用ETag可以正確快取
3. 如果資源修改非常頻繁,在秒以下的時間進行修改,Last-Modified只能精確到秒
複製程式碼
整體流程
求贊,歡迎訪問我的部落格