對瀏覽器作一些緩存



面對瀏覽器,咱們常常須要考慮一些性能的問題,除了讓用戶提升帶寬,咱們還須要經過緩存一些文件來提升用戶體驗。瀏覽器的緩存便是HTTP緩存,咱們打開瀏覽器時總須要與遠程服務器作交互,若是服務器容許的話,瀏覽器首次訪問網站時會把成功的請求結果攔截下來並存儲在內存或硬盤上,以便下次訪問時快速獲取。零零散散看過許多HTTP緩存的文章,因此此次想梳理一下脈絡和本身動手模擬一下服務器看看咱們能夠如何指控瀏覽器緩存咱們的文件。html


DEMO
學習過程當中作了一個小demo模擬緩存過程,能夠在github.com/abigaleypc/…中查看源碼。前端


強緩存 與 協商緩存
HTTP緩存能夠分爲強緩存 與 協商緩存兩大類。強緩存是當咱們發起一個HTTP請求時,前端不會與服務器作交互,而是根據上一次設置的緩存期限,未過時時則再也不向後端作請求,即便文件已經被更新了咱們也沒法獲取。而協商緩存則須要與服務器作一個交互,當服務器告訴咱們上次的緩存並未作修改時,後端則不返回咱們須要的文件,不然返回最新文件。git


強緩存
強緩存包含Expires 與 cache-controlgithub


Expires
表示存在時間,容許客戶端在這個時間以前不去檢查(發請求),例如:Expires: Wed, 21 Oct 2015 07:28:00 GMT
可採用兩種方法對Expires進行設置:web


頁面標籤中設置
html < META HTTP-EQUIV="Expires" VALUE="May 31,2001 13:30:15" >
express

後端設置 npm

Response.Expires=時間(單位:分)來啓用緩存。 // 另外一種方式 Response.AddHeader("expires","utc時刻")後端


以上時間表示消息發送的時間,時間的描述格式由rfc822定義。例如,Web服務器告訴瀏覽器在2018-04-28 03:30:01這個時間點以前,可使用緩存文件。發送請求的時間是2018-04-28 03:25:01,即緩存5分鐘。瀏覽器


理解cache-control
強緩存 - 體驗max-age
「max-age」指令指定從請求的時間開始,容許獲取的響應被重用的最長時間(單位:秒)。若是還有一個 設置了 "max-age" 或者 "s-max-age" 指令的Cache-Control響應頭,那麼 Expires 頭就會被忽略。
下面作一個測試max-age的實驗,打開GitHub的項目並npm start ,測試以前請打開控制檯,將瀏覽器控制檯中的Disable cache關閉。以下圖
緩存


  • Step1: 在入口文件app.js中設置最大緩存時間,以下:
app.use(
 "/public",
    express.static("public", {
        maxAge: "1d"
 }));
複製代碼


  • Step2: 將/public下的靜態文件最大緩存時間設爲一天,如今在/public下的main.js寫了一段更新頁面文本的代碼
window.onload = function() {
 let name = document.getElementById("name");
    name.innerText = "abigale";
};
複製代碼
  • Step3: 第一次打開瀏覽器並打開控制檯,點擊max-age菜單,採用max-age作緩存:瀏覽器查找緩存文件的順序爲 memory - disk - 網絡


  • Step4: 刷新頁面:緩存優先從memory查找,如查找獲得則採用memory中文件


  • Step5: 從新打開頁面:memory若無緩存,則從disk查找


  • Step6: 修改/public/main.js
window.onload = function() {
 let name = document.getElementById("name");
  name.innerText = "AbigaleYu";
};
複製代碼

  • 不管是刷新頁面訪問仍是從新打開頁面訪問,結果與Step4 Step5同樣,name並無更新爲AbigaleYu。這是由於強緩存在緩存時間內並不會去獲取新文件,而是採用緩存文件
    該緩存策略弊端: 當設定時間內更新文件了,瀏覽器並不知道。


其餘value
cache-control 下還有其餘幾個經常使用的value

  • no-cache: 表示每次請求都須要與服務器確認一次,這種狀況通常帶有ETag,當服務器端驗證無修改時,則從緩存中取文件,服務器無需返回文件。
  • no-store: 表示不管如何都不容許客戶端作緩存,每次湊須要作一次完整的請求和完整的響應。
  • public:若是響應被標記爲「public」,則即便它有關聯的 HTTP 身份驗證,甚至響應狀態代碼一般沒法緩存,也能夠緩存響應。大多數狀況下,「public」不是必需的,由於明確的緩存信息(例如「max-age」)已表示響應是能夠緩存的。咱們有時能夠在memory,disk,路由等找到緩存就是由於這是public的設置
  • private:不容許任何中間緩存對其進行緩存,只能最終用戶作緩存

舉一些例子
緩存設置表現max-age=86400瀏覽器以及任何中間緩存都可將響應(若是是「public」響應)緩存長達 1 天(60 秒 x 60 分鐘 x 24 小時)。max-age=86400瀏覽器以及任何中間緩存都可將響應(若是是「public」響應)緩存長達 1 天(60 秒 x 60 分鐘 x 24 小時)。private, max-age=600客戶端的瀏覽器只能將響應緩存最長 10 分鐘(60 秒 x 10 分鐘)。no-store不容許緩存響應,每次請求都必須完整獲取。


引伸問題:from memory cachefrom disk cache 的區別
瀏覽器訪問頁面時,查找靜態文件首先會從緩存中讀取,緩存分爲兩種,內存緩存與硬盤緩存。查找文件的順序爲:memory -> disk -> 服務器。內存緩存是在kill進程時刪除,即關閉瀏覽器時內存緩存消失,而硬盤緩存則是即便關閉瀏覽器也仍然存在。當咱們首次訪問頁面,須要從服務器獲取資源,將可緩存的文件緩存在內存與硬盤,當刷新頁面時(這種狀況沒有關閉瀏覽器)則從內存緩存中讀取,咱們能夠在上面的截圖看到from memory cache的所須要的時間爲0,這是最快的讀取文件方式,當咱們從新開一個頁面時,也就是已經kill這個進程,內存緩存已經消失了,這時候就從硬件緩存獲取,而當咱們手動在瀏覽器清除緩存時,下次訪問就只能再去服務器拉取文件了。但有一點能夠從上面圖中看到,並非從硬盤獲取緩存的時間必定比從網絡獲取的時間短,示例中的時間是更長的,這取決於網絡狀態和文件大小等因素,從緩存獲取有利有弊,當網絡較差或者文件較大時,從硬盤緩存獲取能夠給用戶較好的體驗。

協商緩存
Last-Modified 與 If-Modified-since

  • Last-Modified 標示這個響應資源的最後修改時間。web 服務器在響應請求時,告訴瀏覽器資源的最後修改時間
  • If-Modify-since 再次向服務器請求時帶上,若是資源已修改,返回 HTTP 200,未被修改,返回 HTTP 304

DEMO : 依然是GitHub的源碼。可切換到菜單 Last Modified / If-Modified-Since 查看

  • Step1: 在app.js入口文件中,咱們經過將 Last-Modified 的頭設置爲操做系統上該文件的上次修改日期來控制緩存js
app.use( "/lastModified", 
   express.static("public/lastModified", { 
      lastModified: true, 
      setHeaders: setCustomCacheControl 
   }) 
);
 
複製代碼
  • Step2: 在路徑爲./public/lastModified/main.js的文件中,讀取文件response header中的 Last-modified 展現出來
window.onload = function() {
 let time = document.getElementById("time");
  time.innerText = document.lastModified;
};
複製代碼
  • Step3: 點擊菜單Last Modified / If-Modified-Since,第一次請求狀態碼是意料中的200,但能夠看到響應頭response header多了Last-modified 記錄咱們最後修改文件的時間



  • Step4: 再次刷新頁面時,狀態碼更新爲304(Not Modified),但不一樣與max-age,此處的304雖然是文件並未被修改,但依然須要類似的請求時間,這是由於協商緩存須要向服務器諮詢文件是否被更新,並且能夠看到該請求中request header 多了 If-Modified-Since 字段,這就是告訴瀏覽器上次文件的修改時間。能夠看到上次修改時間 If-Modified-Since 與 響應頭 response header 中 Last-modified 是一致的,所以返回文件未被修改。




  • Step5: 修改main.js中的內容,並刷新頁面,此次能夠看到main.js的請求不是返回304,而是200,展開main.js請求,也能夠看到request header 中上次修改時間 If-Modified-Since 與 響應頭 response header 中 Last-modified 是不一致的,由於咱們須要獲取到最新文件而不是使用緩存文件。



ETag 和 If-None-Match

  • ETag 告訴瀏覽器當前資源在服務器的惟一標識
  • If-None-Match 再次向服務器請求時帶上,若是資源已修改,返回 HTTP 200,未被修改,返回 HTTP 304

總結
瀏覽器獲取文件的過程以下:




Abigale's blog : Abigale's Blog

相關文章
相關標籤/搜索