Web 快取有很多種,比如資料庫快取、代理伺服器快取、CDN 快取,以及瀏覽器快取。
瀏覽器快取指的是將快取檔案儲存在客戶端,一般是通過 HTTP 進行快取。
HTTP 快取機制
HTTP/1.1 標準中固定了 HTTP 快取的兩種方式: expiration 機制 和 validation 機制。前者是通過減少伺服器和瀏覽器的迴圈次數,後者通過只響應頭部資訊較少網路頻寬。(有些參考資料,將前者稱為強快取,後者稱為協商快取)
強快取優先順序高於協商快取,也就是說,當執行強快取的規則,快取生效,則不再執行協商快取。
expiration Model — 強快取
expiration 機制通過 Expires
和 Cache-Control
兩個欄位來標明失效規則。
Expires
Expires 的值為伺服器返回的到期時間,即下一次請求時,請求時間小於伺服器返回的到期時間,直接使用快取資料。但是由於客戶端和伺服器可能有時間差,會導致較大的快取命中誤差,所以 HTTP/1.1 使用了 Cache-Control
替代。
Cache-Control
Cache-Control 是非常重要的規則。取值如下:
- private: 預設取值,表示客戶端可以快取
- public: 客戶端和代理伺服器都可以快取
- max-age: 快取內容會在 xxx 秒後失效
- no-cache: 快取前確認必須先確認其有效性
- no-store: 所有內容都不會快取
注意,Cache-Control 是一個通用的首部欄位。所以,取值對客戶端和伺服器端含義會有所不同。
應用 HTTP/1.1 版本的快取伺服器同時存在 Expires 首部欄位的情況時,會優先處理 max-age 指令,而忽略 Expires 首部欄位。
強快取請求資料流程如下: 客戶端向快取伺服器(快取資料庫)請求資料,如果有快取資料且未失效,則返回資料。如果沒有快取資料或快取資料失效,則向伺服器請求資料,伺服器返回資料和快取規則,客戶端收到並將資料和快取規則存入快取。
validation Model — 協商快取
協商快取的方式是客戶端傳送請求驗證快取標識所對應的資料是否失效,如果伺服器判斷資料有效,則返回一個 304 狀態碼(即報文首部和狀態行),而不用返回報文主體。協議中規定了兩種快取標識。
Last-Modified/If-Modified-Since
客戶端第一次請求伺服器時,伺服器在響應報文的首部通過 Last-Modified
欄位告知瀏覽器資源的最後修改時間。
再次請求時,客戶端在請求報文的首部新增 If-Modified-Since
欄位,該欄位的值是上次請求時,伺服器返回的 Last-Modified
的值。
伺服器收到請求發現有 If-Modified-Since 則與被請求資源的最後修改時間進行比對,若資源的最後修改時間大於 If-Modified-Since 所提供的值,說明資源被改動過,則響應資源內容,返回狀態碼 200。否則,說明資源沒有被改動,則返回 304,告知瀏覽器可以使用所儲存的 cache。
Etag/If-None-Match 優先順序高於 Last-Modified/If-Modified-Since
客戶端第一次請求伺服器時,伺服器在響應報文的首部通過 Etag
欄位告知瀏覽器當前資源在伺服器的唯一標識(生成規則由伺服器決定)。
同理,再次請求時,快取資料的唯一標識被新增到請求報文的 If-None-Match
欄位中。
伺服器收到請求發現有 If-None-Match 則與被請求資源的唯一標識進行比對,不同,說明資源被修改過,返回 200。相同,則說明資源未被修改,返回 304。
為什麼需要 Etag?
Etag 的出現是為了解決 Last-Modified/If-Modified-Since 比較難以解決的問題。比如:
- 一些檔案會週期性地更改,但是內容並不會改變,只是改變修改時間,這個時候我們不太需要客戶端認為檔案內容被修改過了,而請求資源
- 某些檔案修改非常頻繁(指的是內容),比如每秒之內修改了多次,If-Modified-Since 能檢查到的粒度是秒級,這種修改可能導致無法判定。
所以,Etag 的優先順序高於 Last-Modified 也是應該的。但是,效能上,Etag 要遜於 Last-Modified,因為 Last-Modified 指記錄修改的時間值,而 Etag 的值需要演算法計算一個 hash 值。
HTTP 快取過程總結
- 瀏覽器第一次載入資源,伺服器返回 200,並將資料和快取規則存入快取。
- 再次請求資源時,如果當前時間和上一次返回 200 的時間差不超過 Cache-Control 設定的 max-age,則沒有過期,命中快取(如果瀏覽器不支援 HTTP/1.1,則用 expires 判斷是否過期)。如果時間過期,則向伺服器傳送 If-None-Match 和 If-Modified-Since 請求。
- 伺服器收到請求,首先根據 Etag 的值判斷被請求的檔案有沒有被修改,Etag 值一致,則命中協商快取,返回304;如果不一致,返回新的資源的快取規則和狀態碼,並返回 200。
- 如果伺服器收到的請求沒有 Etag 值,則將 If-Modified-Since 和被請求的檔案的最後修改時間做對比,一致則命中協商快取,返回 304;否則返回新的 Last-Modified 和資料,返回 200。
使用者操作對快取的影響
對於一下操作,如位址列回車、頁面連結跳轉、新開視窗、前進和回退,兩種機制( expires/validation )都是有效的。
F5 重新整理操作,Expires/Cache-Control 是無效的,Last-Modified/Etag 是有效的,也就是說強制協商快取。
Ctrl + F5 強制重新整理,兩者都是無效的。
抓包工具: Fiddler
檢視 chrome 快取
chrome://view-http-cache/
參考: 徹底弄懂HTTP快取機制及原理
HTML5 應用快取
應用快取(application cache),簡稱 appcache,是專門為開發離線 Web 應用設計的。它是從瀏覽器的快取中分出來的一塊快取區,使用一個 manifest
檔案,列出要下載和快取的資源。
第二步, 在需要離線使用的頁面中新增 manifest 屬性,用於指定快取清單檔案的路徑。比如:
<html manifest="/offline.manifest">
複製程式碼
資料儲存
隨著 Web 應用的出現,也產生了能夠直接在客戶端上儲存使用者資訊能力的要求。
Cookie 是在客戶端儲存資料的其中一種選項。
Cookie
Cookie 的工作機制是使用者識別及狀態管理。它是怎樣工作的呢?比如,當要對某個使用者進行識別的時候,伺服器對任意的 HTTP 請求傳送 Set-Cookie
首部欄位作為響應的一部分。
HTTP/1.1 200 OK
Content-type: text/html
Set-Cookie: name=value
...
複製程式碼
這之後,瀏覽器的每個請求都新增 Cookie
欄位將資訊傳送回伺服器。伺服器就知道你是屬於哪個使用者了。
GET /index.html HTTP/1.1
Cookie: name=value
...
複製程式碼
Set-Cookie 欄位的屬性
- name 名稱 一個唯一確定的 cookie 的名稱,名稱必須被 URL 編碼
- value 值 儲存在 cookie 中的字串的值。值必須被 URL 編碼
- domain 域名 確定 cookie 有效的域,所有向該域傳送的請求中都包含這個 cookie 資訊
- path 路徑 對於制定域中的那個路徑,才應該向伺服器傳送 cookie
- expire 失效時間
- secure 安全標識 指定後,cookie 只能在使用 SSL 連線時(即HTTPS通訊時)才傳送到伺服器
- HttpOnly 它使得附加在 HttpOnly 屬性後的 Cookie 內容無法被 JavaScript 讀取,可以防止 XSS 攻擊
Cookie 欄位只包含 Cookie
屬性。該屬性在請求中包含從伺服器接收到的 Cookie,接收到多個 Cookie 時,同樣可以以多個 Cookie 形式傳送。
值得注意的時,為了不會佔據太多磁碟空間,每個域的 cookie 總數有限的,不同瀏覽器之間各有不同。此外,對於 cookie 的尺寸也有限制。
另外,避免在 cookie 中儲存敏感資訊。
Web Storage
Web Storage 是 HTML5 的一部分,目的是克服由 cookie 帶來的一些限制。
- 提供一種在 cookie 之外儲存會話資料的途徑
- 提供一種儲存大量可以跨會話存在的資料的機制
Web Storage 提供兩種用於儲存資料的物件,sessionStorage
物件和 localStorage
物件。
sessionStorage
sessionStorage 物件儲存特定於某個會話的資料,該資料只保持到瀏覽器關閉。儲存在 sessionStorage 中的資料可以跨越頁面重新整理而存在。
另外,sessionStorage 物件應該主要用於僅針對會話的小段資料的儲存。如果需要跨越會話儲存資料,那麼 localStorage 更合適。
localStorage
儲存在 localStorage 中的資料保留到通過 JavaScript 刪除或者是使用者清除瀏覽器快取。同時,localStorage 支援同源策略。也就是說,要訪問同一個 localStorage 物件,頁面必須來自同一個域。
同理,和其他客戶端儲存方案類似,Web Storage 也有大小限制,因瀏覽器而異。
IndexedDB
IndexedDB 是在瀏覽器中儲存結構化資料的一種資料庫。
參考: