淺談瀏覽器緩存

最近在項目中遇到了IE瀏覽器因緩存問題未能成功向後端發送GET類型請求的bug,而後順藤摸瓜順便看了看緩存的知識,以爲有必要總結一下。php

在前端開發中,性能一直都是被你們所重視的一點,然而判斷一個網站的性能最直觀的就是看網頁打開的速度。其中提升網頁反應速度的一個方式就是使用緩存。一個優秀的緩存策略能夠縮短網頁請求資源的距離,減小延遲,而且因爲緩存文件能夠重複利用,還能夠減小帶寬,下降網絡負荷。css

1. 介紹

web緩存是指一個web資源(如html頁面,圖片,js,數據等)存在於web服務器和客戶端(瀏覽器)之間的副本。html

緩存會根據進來的請求保存輸出內容的副本;當下一個請求來到的時候,若是是相同的URL,緩存會根據緩存機制決定是直接使用副本響應訪問請求,仍是向源服務器再次發送請求。比較常見的就是瀏覽器會緩存訪問過網站的網頁,當再次訪問這個URL地址的時候,若是網頁沒有更新,就不會再次下載網頁,而是直接使用本地緩存的網頁。只有當網站明確標識資源已經更新,瀏覽器纔會再次下載網頁。至於瀏覽器和網站服務器是如何標識網站頁面是否更新的機制,將在後面介紹。前端

1.1 web緩存的做用

web緩存的做用顯而易見:web

  1. 減小網絡帶寬消耗
    不管對於網站運營者或者用戶,帶寬都表明着金錢,過多的帶寬消耗,只會便宜了網絡運營商。當Web緩存副本被使用時,只會產生極小的網絡流量,能夠有效的下降運營成本。
  2. 下降服務器壓力
    給網絡資源設定有效期以後,用戶能夠重複使用本地的緩存,減小對源服務器的請求,間接下降服務器的壓力。同時,搜索引擎的爬蟲機器人也能根據過時機制下降爬取的頻率,也能有效下降服務器的壓力。
  3. 減小網絡延遲,加快頁面打開速度
    帶寬對於我的網站運營者來講是十分重要,而對於大型的互聯網公司來講,可能有時由於錢多而真的不在意。那Web緩存還有做用嗎?答案是確定的,對於最終用戶,緩存的使用可以明顯加快頁面打開速度,達到更好的體驗。

1.2 web緩存的類型

web緩存大體能夠分爲如下幾種類型數據庫

  1. 數據庫數據緩存
  2. 服務器端緩存
  3. 瀏覽器端緩存
  4. web應用層緩存

瀏覽器經過代理服務器向源服務器發起請求的原理以下圖:後端

clipboard.png

瀏覽器先向代理服務器發起web請求,再將請求轉發到源服務器。它屬於共享緩存,因此不少地方均可以使用其緩存資源,所以對於節省流量有很大做用。瀏覽器

瀏覽器緩存是將文件保存在客戶端,在同一個會話過程當中會檢查緩存的副本是否足夠新,在後退網頁時,訪問過的資源能夠從瀏覽器緩存中拿出使用。經過減小服務器處理請求的數量,用戶將得到更快的體驗緩存

下面着重關注一下瀏覽器緩存。安全

2. web緩存的工做原理

全部的緩存都是基於一套規則來幫助他們決定何時使用緩存中的副本提供服務(假設有副本可用的狀況下,未被銷燬回收或者未被刪除修改)。這些規則有的在協議中有定義(如HTTP協議1.0和1.1),有的則是由緩存的管理員設置(如DBA、瀏覽器的用戶、代理服務器管理員或者應用開發者)。

2.1 瀏覽器端的緩存規則

對於瀏覽器端的緩存來說,這些規則是在HTTP協議頭和HTML頁面的Meta標籤中定義的。他們分別從新鮮度校驗值兩個維度來規定瀏覽器是直接使用緩存中的副本,仍是須要去源服務器獲取更新的版本。

  1. 新鮮度(過時機制):也就是緩存副本有效期。一個緩存副本必須知足如下任一條件,瀏覽器會認爲它是有效的,足夠新的,而直接從緩存中獲取副本並渲染:

    • 含有完整的過時時間控制頭信息(HTTP協議報頭),而且仍在有效期內
    • 瀏覽器已經使用過這個緩存副本,而且在一個會話中已經檢查過新鮮度
  2. 校驗值(驗證機制):服務器返回資源的時候有時在控制頭信息帶上這個資源的實體標籤Etag(Entity Tag),它能夠用來做爲瀏覽器再次請求過程的校驗標識。如過發現校驗標識不匹配,說明資源已經被修改或過時,瀏覽器需求從新獲取資源內容。

2.2 瀏覽器緩存的控制

2.2.1 使用HTML的 Meta 標籤

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

上述代碼的做用是告訴瀏覽器當前頁面不被緩存,每次訪問都須要去服務器拉取。使用上很簡單,但只有部分瀏覽器能夠支持,並且全部緩存代理服務器都不支持,由於代理不解析HTML內容自己。
能夠經過這個頁面測試你的瀏覽器是否支持:Pragma No-Cache Test

2.2.2 使用緩存有關的HTTP消息報頭

一個URI的完整HTTP協議交互過程是由HTTP請求和HTTP響應組成的。有關HTTP詳細內容可參考《Hypertext Transfer Protocol — HTTP/1.1》《HTTP協議詳解》等。

在HTTP請求和響應的消息報頭中,常見的與緩存有關的消息報頭有:

clipboard.png

  1. Cache-Control
    cache-control的種類這麼多,然而怎麼使用它們呢:
    clipboard.png

    1. max-age(單位爲s)指定設置緩存最大的有效時間,定義的是時間長短。當瀏覽器向服務器發送請求後,在max-age這段時間裏瀏覽器就不會再向服務器發送請求了。
      咱們來找個資源看下。好比QQ推廣上的css資源,max-age=3600,也就是說緩存有效期爲3600秒(也就是1h)。因而在1小時內都會使用這個版本的資源,即便服務器上的資源發生了變化,瀏覽器也不會獲得通知。max-age會覆蓋掉Expires,後面會有討論。

      clipboard.png

    2. s-maxage(單位爲s)同max-age,只用於共享緩存(好比CDN緩存)。
      好比,當s-maxage=60時,在這60秒中,即便更新了CDN的內容,瀏覽器也不會進行請求。也就是說max-age用於普通緩存,而s-maxage用於代理緩存。若是存在s-maxage,則會覆蓋掉max-age和Expires header。
    3. public 指定響應會被緩存,而且在多用戶間共享。也就是下圖的意思。若是沒有指定public仍是private,則默認爲public。

      clipboard.png

    4. private 響應只做爲私有的緩存(見下圖),不能在用戶間共享。若是要求HTTP認證,響應會自動設置爲private。

      clipboard.png

    5. no-cache 指定不緩存響應,代表資源不進行緩存,可是設置了no-cache以後並不表明瀏覽器不緩存,而是在獲取緩存前要向服務器確認資源是否被更改。所以有的時候只設置no-cache防止緩存仍是不夠保險,還能夠加上private指令,將過時時間設爲過去的時間。
    6. no-store 絕對禁止緩存,一看就知道若是用了這個命令固然就是不會進行緩存啦~每次請求資源都要從服務器從新獲取。
    7. must-revalidate 指定若是頁面是過時的,則去服務器進行獲取。這個指令並不經常使用,就不作過多的討論了。
  2. Expires
    緩存過時時間,用來指定資源到期的時間,是服務器端的具體的時間點。也就是說, Expires=max-age + 請求時間 ,須要和Last-modified結合使用。但在上面咱們提到過,cache-control的優先級更高。 Expires是Web服務器響應消息頭字段,在響應http請求時告訴瀏覽器在過時時間前瀏覽器能夠直接從瀏覽器緩存取數據,而無需再次請求。

    clipboard.png

  3. Last-modified & If-modified-since
    服務器端文件的最後修改時間,須要和cache-control共同使用,是檢查服務器端資源是否更新的一種方式。當瀏覽器再次進行請求時,會向服務器傳送If-Modified-Since報頭,詢問Last-Modified時間點以後資源是否被修改過。若是沒有修改,則返回碼爲304,使用緩存;若是修改過,則再次去服務器請求資源,返回碼和首次請求相同爲200,資源爲服務器最新資源。
  4. Etag & & If-None-Match
    根據實體內容生成一段hash字符串,標識資源的狀態,由服務端產生。瀏覽器會將這串字符串傳回服務器,驗證資源是否已經修改,若是沒有修改,過程以下:

    clipboard.png

2.2.3 緩存報頭種類與優先級

  1. Cache-Control與Expires
    Cache-ControlExpires的做用一致,都是指明當前資源的有效期,控制瀏覽器是否直接從瀏覽器緩存取數據仍是從新發請求到服務器取數據。只不過Cache-Control的選擇更多,設置更細緻,若是同時設置的話,其優先級高於Expires
  2. Last-Modified與ETag
    Etag是服務器自動生成或者由開發者生成的對應資源在服務器端的惟一標識符,可以更加準確的控制緩存。Last-Modified與ETag是能夠一塊兒使用的,服務器會優先驗證ETag,一致的狀況下,纔會繼續比對Last-Modified,最後才決定是否返回304。
    你可能會以爲使用Last-Modified已經足以讓瀏覽器知道本地的緩存副本是否足夠新,爲何還須要Etag(實體標識)呢?HTTP1.1中Etag的出現主要是爲了解決幾個Last-Modified比較難解決的問題:

    • Last-Modified標註的最後修改只能精確到級,若是某些文件在1秒鐘之內,被修改屢次的話,它將不能準確標註文件的新鮮度
    • 若是某些文件會被按期生成,當有時內容並無任何變化,但Last-Modified卻改變了,致使文件無法使用緩存
    • 有可能存在服務器沒有準確獲取文件修改時間,或者與代理服務器時間不一致等情形
  3. Last-Modified/ETag 與 Cache-Control/Expires
    配置Last-Modified/ETag的狀況下,瀏覽器再次訪問統一URI的資源,仍是會發送請求到服務器詢問文件是否已經修改,若是沒有,服務器會只發送一個304回給瀏覽器,告訴瀏覽器直接從本身本地的緩存取數據;若是修改過那就整個數據從新發給瀏覽器;
    Cache-Control/Expires則不一樣,若是檢測到本地的緩存仍是有效的時間範圍內,瀏覽器直接使用本地副本,不會發送任何請求。二者一塊兒使用時,Cache-Control/Expires的優先級要高,即當本地副本根據Cache-Control/Expires發現還在有效期內時,則不會再次發送請求去服務器詢問修改時間Last-Modified或實體標識Etag了。
    通常狀況下,二者會配合一塊兒使用,由於即便服務器設置緩存時間, 當用戶點擊「刷新」按鈕時,瀏覽器會忽略緩存繼續向服務器發送請求,這時Last-Modified/ETag將可以很好利用304,從而減小響應開銷。

2.2.4 哪些請求不能被緩存?

沒法被瀏覽器緩存的請求:

  • HTTP信息頭中包含Cache-Control:no-cache,pragma:no-cache,或Cache-Control:max-age=0等告訴瀏覽器不用緩存的請求
  • 須要根據Cookie,認證信息等決定輸入內容的動態請求是不能被緩存的
  • 通過HTTPS安全加密的請求(有人也通過測試發現,ie其實在頭部加入Cache-Control:max-age信息,firefox在頭部加入Cache-Control:Public以後,可以對HTTPS的資源進行緩存,參考《HTTPS的七個誤解》)
  • POST請求沒法被緩存
  • HTTP響應頭中不包含Last-Modified/Etag,也不包含Cache-Control/Expires的請求沒法被緩存

3. 使用緩存流程

一個用戶發起一個靜態資源請求的時候,瀏覽器會經過如下幾步來獲取並展現資源:

clipboard.png

緩存行爲主要由緩存策略決定,而緩存策略由內容擁有者設置。這些策略主要經過特定的HTTP頭部來清晰地表達。

以上過程也能夠被歸納爲三個階段:

  1. 本地緩存階段:先在本地查找該資源,若是有發現該資源,並且該資源尚未過時,就使用這一個資源,徹底不會發送http請求到服務器;
  2. 協商緩存階段:若是在本地緩存找到對應的資源,可是不知道該資源是否過時或者已通過期,則發一個http請求到服務器,而後服務器判斷這個請求,若是請求的資源在服務器上沒有改動過,則返回304,讓瀏覽器使用本地找到的那個資源;
  3. 緩存失敗階段:當服務器發現請求的資源已經修改過,或者這是一個新的請求(在原本沒有找到資源),服務器則返回該資源的數據,而且返回200, 固然這個是指找到資源的狀況下,若是服務器上沒有這個資源,則返回404。

4. 用戶操做行爲與緩存的關係

用戶在使用瀏覽器的時候,會有各類操做,好比輸入地址後回車,按F5刷新等,這些行爲會對緩存有什麼影響呢?

clipboard.png

經過上表咱們能夠看到,當用戶在按F5進行刷新的時候,會忽略Expires/Cache-Control的設置,會再次發送請求去服務器請求,而Last-Modified/Etag仍是有效的,服務器會根據狀況判斷返回304仍是200;
而當用戶使用Ctrl+F5進行強制刷新的時候,只是全部的緩存機制都將失效,從新從服務器拉去資源。

  • 普通刷新 – 當按下F5或者點擊刷新按鈕來刷新頁面的時候,瀏覽器將繞過本地緩存來發送請求到服務器, 此時, 協商緩存是有效的
  • 強制刷新 – 當按下ctrl+F5來刷新頁面的時候, 瀏覽器將繞過各類緩存(本地緩存和協商緩存), 直接讓服務器返回最新的資源
  • 回車或轉向 – 當在地址欄上輸入回車或者按下跳轉按鈕的時候, 全部緩存都生效

5. 如何從緩存角度改善站點

詳細信息

  • 同一個資源保證URL的穩定性
  • 給css、js、圖片等資源增長HTTP緩存頭,並強制入口html不被緩存
  • 減小對Cookie的依賴
  • 減小對HTTPS加密協議的使用
  • 多用Get方式請求動態Cgi
  • 動態CGI也是能夠被緩存

網上的帖子大多深淺不一,甚至有些先後矛盾,在下的文章都是學習過程當中的總結,若是發現錯誤,歡迎留言指出~

參考:
Web緩存機制系列
淺談web緩存
Web先後端緩存技術
瀏覽器緩存機制:不一樣瀏覽器對用戶操做行爲處理比較

PS:歡迎你們關注個人公衆號【前端下午茶】,一塊兒加油吧~

另外能夠加入「前端下午茶交流羣」微信羣,長按識別下面二維碼便可加我好友,備註加羣,我拉你入羣~

相關文章
相關標籤/搜索