Web緩存 - HTTP協議緩存

爲何要使用 Web 緩存

Web緩存通常分爲瀏覽器緩存、代理服務器緩存以及網關緩存,本文主要講的是 瀏覽器緩存,其它兩種緩存你們自行去了解下。javascript

Web 緩存遊走於服務器和客戶端之間。這個服務器多是源服務器(資源所駐留的服務器),數量多是1個或多個;這個客戶端也多是1個或多個。Web 緩存就在服務器-客戶端之間搞監控,監控請求,而且把請求輸出的內容(例如html頁面、 圖片和文件)(統稱爲副本)另存一份;而後,若是下一個請求是相同的 URL,則直接請求保存的副本,而不是再次麻煩源服務器。css

使用緩存的2個主要緣由:html

  • 下降延遲:緩存離客戶端更近,所以,從緩存請求內容比從源服務器所用時間更少,呈現速度更快,網站就顯得更靈敏。
  • 下降網絡傳輸:副本被重複使用,大大下降了用戶的帶寬使用,其實也是一種變相的省錢(若是流量要付費的話),同時保證了帶寬請求在一個低水平上,更容易維護了。

試想如今的大型網站,隨便一個頁面都是一兩百個請求,天天 pv 都是億級別,若是沒有緩存,用戶體驗會急劇降低(表如今等待請求的時間上)、同時服務器壓力和網絡帶寬都面臨嚴重的考驗。html5

瀏覽器緩存控制機制

瀏覽器緩存控制機制有三種:HTML5離線存儲和本地緩存、HTML Meta 標籤、HTTP 協議緩存。java

HTML5離線存儲和本地緩存

該種緩存機制是運用 HTMl5 新推出一些支持離線應用的 API 來進行數據的緩存,好比 appcache、sessionStorage、localStorage等等。web

appcache 經過定義一個描述文件(manifest file)來列出要下載和緩存的資源,manifest file 示例以下:json

CACHE MANIFEST
# Comment

file.js
file.css

而後在 html 中引用:瀏覽器

<html manifest="./xxx.manifest">

sessionStorage、localStorage 的基本用法以下:緩存

// localStorage 用法類似
sessionStorage.set('name', 'laixiangran') // 存儲數據
sessionStorage.get('name') // 獲取數據 'laixiangran'

本文暫時就不詳細介紹,後面我會單獨介紹這塊的內容。安全

HTML Meta 標籤

使用 HTML Meta 標籤,Web 開發者能夠在 HTML 頁面的 <head> 節點中加入 <meta> 標籤,代碼以下:

<META HTTP-EQUIV="Pragma" CONTENT="no-cache">

上述代碼的做用是告訴瀏覽器當前頁面不被緩存,每次訪問都須要去服務器拉取。

使用上很簡單,但只有部分瀏覽器能夠支持,並且全部緩存代理服務器都不支持,由於代理不解析 HTML 內容自己。

HTTP 協議緩存

HTTP 協議緩存是咱們本文講解的重點,它是經過 HTTP 頭信息來控制緩存的,HTTP 頭信息可讓你對瀏覽器和代理服務器如何處理你的副本進行更多的控制。他們在 HTML 代碼中是看不見的,通常由 Web 服務器自動生成。可是,根據你使用的服務器,你能夠在某種程度上進行控制。

瀏覽器請求流程

瀏覽器第一次請求流程圖:

該流程比較簡單了,瀏覽器在第一次請求的時候不存在緩存,直接從瀏覽器請求,等請求返回結果以後再根據 HTTP 頭信息將數據緩存在內存或者硬盤中。

瀏覽器再次請求時:

該流程就複雜多了,瀏覽器須要根據 HTTP 頭信息來判斷是否直接從緩存讀取數據仍是交由服務器來判斷是否從緩存讀取數據。

幾種狀態碼的區別:

下面咱們就從該流程中出現的 HTTP 狀態碼 200(from cache)和 304 來說解 HTTP 協議緩存中的 HTTP 頭信息。

200(from cache)

這種 HTTP 狀態碼錶示不訪問服務器,直接從緩存(內存或者硬盤)讀取數據。

看兩張圖:

從上面兩張圖,咱們會看到狀態碼有點不同,分別是 200(from memory cache) 以及 200(from diks cache),這兩個的區別一個是從內存讀取數據,一個是從硬盤讀取數據,而後它們的前後順序是先從內存讀取,再從硬盤讀取。這裏咱們就統稱爲 200(from cache)

出現 200(from cache) 這種狀況,咱們須要關注 ExpiresCache-control 這兩種HTTP 頭信息字段。

Expires

Expires 的中文意思是「有效期」。顯然,就是告訴瀏覽器緩存的有效期。若是過時,緩存會檢查源服務器以肯定文件是否改變了。

Expires 頭惟一的有效值是 HTTP 時間,其餘值無效,不會去緩存的。注意:時間是格林威治時間(GMT),而不是本地時間。以下所示:

Expires: Mon, 29 Oct 2018 03:53:10 GMT

那麼看咱們上面的兩張圖中的 Expires,它都是到 2018-10-29 03:53:10 過時,而咱們本次請求的時間 Date 是 2018-04-29 03:53:10,所以本次請求直接從緩存讀取數據,返回 200(from cache)。

儘管 Expires 頭頗有用,但它有必定的侷限性:

  • 由於牽扯到時間,Web 服務器端的時間必須和緩存的同步,不然極可能實現不了預期的結果 —— 緩存把過時的數據當成最新的數據,把最新的數據看成過時的數據。
  • 你很容易忘記給某內容設置了一個特定時間,若是返回內容的時候沒有更新這個過時時間,則每一個請求都是上訪到服務器,反而增長了負載和響應時間。
  • 最後呢,Expires 是 HTTP 1.0 的東西,如今默認瀏覽器均默認使用 HTTP 1.1,因此它的做用基本忽略。
Cache-Control

Cache-Control 與 Expires 的做用一致,都是指明當前資源的有效期,控制瀏覽器是否直接從瀏覽器緩存讀取數據仍是從新發請求到服務器讀取數據。只不過 Cache-Control 的選擇更多,設置更細緻,若是同時設置的話,其優先級高於 Expires。

Cache-Control 有用的響應頭包括:

  • max-age=[秒]: 表示在這個時間範圍內緩存是新鮮的無需更新。相似 Expires 時間,不過這個時間是相對的,而不是絕對的。也就是某次請求成功後多少秒內緩存是新鮮的。
  • s-maxage=[秒]: 相似 max-age, 除了僅應用於共享緩存(如代理)。
  • public: 標記認證的響應纔可以被緩存。通常而言,須要認證 HTTP 請求內容會自動私有化(不會被緩存)。
  • privateN: 容許緩存專門爲某一個用戶存儲響應,比方說在瀏覽器中;共享緩存通常不會,例如在代理中。
  • no-cache: 每次在釋放緩存副本以前都強制發送請求給源服務器進行驗證,這在確保認證有效性上很管用(和 public 結合使用)或者保證內容必須是即時的,不得無視緩存的全部優勢,如國內的微博、twitter等的刷新顯示。
  • no-store: 強制緩存在任何狀況下都不要保留任何副本。
  • must-revalidate: 告訴緩存,我給你準備了一些關於新鮮度的信息,在表現的時候要嚴格遵循。HTTP 容許緩存在某些特定狀況下返回過時數據,指定了這個屬性,相對於告訴緩存,你必須嚴格遵循個人規則。
  • proxy-revalidate: 相似 must-revalidate,除了只能應用於代理緩存。

使用以下所示:

Cache-Control: max-age=15811200

那麼看咱們上面的兩張圖中的 Cache-Control,它在當前請求成功後15811200秒內都是有效的,所以本次請求直接從緩存讀取數據,返回 200(from cache)。若是從當前請求成功開始,過了15811200秒以後就會從新從服務器請求新數據。

304

當瀏覽器經過 Expires 或者 Cache-control 判斷出緩存已通過期,那麼就須要從新發送請求到服務器,讓服務器判斷當前緩存是否能夠繼續使用。

當服務器判斷該緩存已經失效,那麼就會返回新數據,HTTP 狀態碼爲 200;

當瀏覽器判斷該緩存還未失效,那麼就會返回 HTTP 狀態碼爲 304 (無需包體,節省流量),告知瀏覽器繼續使用緩存。

那麼經過哪些 HTTP 頭信息字段來判斷是否返回 200 仍是 304 呢?那麼咱們就請出接下來的主角: Last-Modified/If-Modified-SinceEtag/If-None-Match。這兩個字段都須要配合 Cache-Control 使用。

Last-Modified/If-Modified-Since
  • Last-Modified: 標示這個響應資源的最後修改時間。web 服務器在響應請求時,告訴瀏覽器資源的最後修改時間。

  • If-Modified-Since: 當資源過時時(使用 Cache-Control 標識的 max-age),發現資源具備 Last-Modified 聲明,則再次向 web 服務器請求時帶上 If-Modified-Since,表示請求時間。web服務器收到請求後發現有 If-Modified-Since 則與被請求資源的最後修改時間進行比對。若最後修改時間較新,說明資源有被改動過,則響應資源內容(寫在響應消息包體內),HTTP 200;若最後修改時間較舊,說明資源無新修改,則響應 HTTP 304 (無需包體,節省流量),告知瀏覽器繼續使用緩存。

Etag/If-None-Match

這是在 HTTP 1.1 中引入了一個新的驗證器。

  • Etag: web 服務器響應請求時,告訴瀏覽器當前資源在服務器的惟一標識(生成規則由服務器決定)。Apache 中,ETag 的值,默認是對文件的索引節(INode),大小(Size)和最後修改時間(MTime)進行 Hash 後獲得的。

  • If-None-Match: 當資源過時時(使用 Cache-Control 標識的 max-age),發現資源具備 Etage 聲明,則再次向 web 服務器請求時帶上 If-None-Match (Etag 的值)。web 服務器收到請求後發現有 If-None-Match 則與被請求資源的相應校驗串進行比對,決定返回 200 或 304。

Etag 優先於 Last-Modified

你可能會以爲使用 Last-Modified 已經足以讓瀏覽器知道本地的緩存副本是否足夠新,爲何還須要 Etag(實體標識)呢?HTTP1.1 中 Etag 的出現主要是爲了解決幾個 Last-Modified 比較難解決的問題:

  • Last-Modified 標註的最後修改只能精確到秒級,若是某些文件在1秒鐘之內,被修改屢次的話,它將不能準確標註文件的修改時間。

  • 若是某些文件會被按期生成,當有時內容並無任何變化,但Last-Modified卻改變了,致使文件無法使用緩存。

  • 有可能存在服務器沒有準確獲取文件修改時間,或者與代理服務器時間不一致等情形。

Etag 是服務器自動生成或者由開發者生成的對應資源在服務器端的惟一標識符,可以更加準確的控制緩存。Last-Modified 與 ETag 是能夠一塊兒使用的,服務器會優先驗證 ETag,一致的狀況下,纔會繼續比對 Last-Modified,最後才決定是否返回 304。

建立支持緩存網站的小技巧

經過上面的介紹,咱們知道 HTTP 協議緩存的機制,目的就是讓你能夠更靈活更細緻的控制瀏覽器緩存,從而讓你的網站的緩存更加友好,用戶體驗更完美。

下面這些技巧也可讓你網站的緩存更加友好:

  • 保持URL穩定: 這是緩存的金科玉律,若是你爲不一樣頁面,不一樣用戶或不一樣網站提供相同的內容,他們應該使用相同的URL。 這是簡單卻很是行之有效的方法。例如,你的 HTML 中的某個引用地址是"/index.html", 則要一直使用這個地址。
  • 不一樣地方的圖片和其餘元素 使用同一庫
  • 對於不常常改變的圖片/頁面啓用緩存,經過將 Cache-Control: max-age 頭信息的值設大一點。
  • 對於按期更新的內容經過指定 max-age 或過時時間實現緩存。
  • 若是資源改變了(尤爲下載文件),改變其名字。因爲通常這種資源會有很長的過時時間,而服務器上一直是正確的版本;所以,連接這個下載資源的頁面須要要比較短的過時時間。不然,會出現服務器的資源是新的,但頁面被緩存了,其中的連接地址仍是舊的,就會出現新舊版本衝突的可能。
  • 萬不得已不要變更文件: 不然你要設置一個新的 Last-Modified 值。另外,當你更新站點的時候,只要上傳改動的那些文件,而不要把整個站點都覆蓋過去。
  • Cookie能不用就不用: Cookie 難以被緩存,且大多情境下是沒有必要的。若是你非得使用 Cookie,建議用在動態頁面上。
  • 減小SSL的使用: 由於共享緩存不能存儲認證頁面,只在必要的時候使用,而且在 SSL 頁面上減小圖片的使用。

SSL:全稱 Secure Socket Layer – 安全套接層,爲 Netscape 所研發,用以保障在 Internet 上數據傳輸之安全,利用數據加密 (Encryption) 技術,可確保數據在網絡上的傳輸過程當中不會被截取及竊聽。目前通常通用的規格爲 40 bit 的安全標準,美國則已推出 128 bit 的更高安全標準,但限制出境。只要 3.0 版本以上的 I.E. 或 Netscape 瀏覽器便可支持 SSL。

  • 使用 REDbot 檢查你的網站: 能夠幫助你應用本文所介紹的一些概念。

REDbot:REDbot = RED + robot,是個機器人,檢查 HTTP 資源,看他們如何會表現,指出常見的問題,並提出改進建議。雖然它屬於 HTTP 一致性測試儀,但卻能夠找到很多 HTTP 相關問題。

用戶行爲與緩存

用戶的一些行爲會影響到瀏覽器的緩存,具體以下:

完整流程圖

相關文章
相關標籤/搜索