面對瀏覽器,咱們常常須要考慮一些性能的問題,除了讓用戶提升帶寬,咱們還須要經過緩存一些文件來提升用戶體驗。瀏覽器的緩存便是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
關閉。以下圖
緩存
app.js
中設置最大緩存時間,以下:app.use(
"/public",
express.static("public", {
maxAge: "1d"
}));
複製代碼
/public
下的靜態文件最大緩存時間設爲一天,如今在/public
下的main.js
寫了一段更新頁面文本的代碼window.onload = function() {
let name = document.getElementById("name");
name.innerText = "abigale";
};
複製代碼
max-age
菜單,採用max-age
作緩存:瀏覽器查找緩存文件的順序爲 memory - disk - 網絡/public/main.js
window.onload = function() {
let name = document.getElementById("name");
name.innerText = "AbigaleYu";
};
複製代碼
Step4
Step5
同樣,name並無更新爲AbigaleYu。這是由於強緩存在緩存時間內並不會去獲取新文件,而是採用緩存文件其餘value
cache-control 下還有其餘幾個經常使用的value
舉一些例子
緩存設置表現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 cache
與 from disk cache
的區別
瀏覽器訪問頁面時,查找靜態文件首先會從緩存中讀取,緩存分爲兩種,內存緩存與硬盤緩存。查找文件的順序爲:memory -> disk -> 服務器。內存緩存是在kill進程時刪除,即關閉瀏覽器時內存緩存消失,而硬盤緩存則是即便關閉瀏覽器也仍然存在。當咱們首次訪問頁面,須要從服務器獲取資源,將可緩存的文件緩存在內存與硬盤,當刷新頁面時(這種狀況沒有關閉瀏覽器)則從內存緩存中讀取,咱們能夠在上面的截圖看到from memory cache的所須要的時間爲0,這是最快的讀取文件方式,當咱們從新開一個頁面時,也就是已經kill這個進程,內存緩存已經消失了,這時候就從硬件緩存獲取,而當咱們手動在瀏覽器清除緩存時,下次訪問就只能再去服務器拉取文件了。但有一點能夠從上面圖中看到,並非從硬盤獲取緩存的時間必定比從網絡獲取的時間短,示例中的時間是更長的,這取決於網絡狀態和文件大小等因素,從緩存獲取有利有弊,當網絡較差或者文件較大時,從硬盤緩存獲取能夠給用戶較好的體驗。
協商緩存
Last-Modified 與 If-Modified-since
DEMO : 依然是GitHub的源碼。可切換到菜單 Last Modified / If-Modified-Since 查看
app.js
入口文件中,咱們經過將 Last-Modified 的頭設置爲操做系統上該文件的上次修改日期來控制緩存js
app.use( "/lastModified",
express.static("public/lastModified", {
lastModified: true,
setHeaders: setCustomCacheControl
})
);
複製代碼
./public/lastModified/main.js
的文件中,讀取文件response header中的 Last-modified 展現出來window.onload = function() {
let time = document.getElementById("time");
time.innerText = document.lastModified;
};
複製代碼
Last Modified / If-Modified-Since
,第一次請求狀態碼是意料中的200,但能夠看到響應頭response header多了Last-modified 記錄咱們最後修改文件的時間ETag 和 If-None-Match
總結
瀏覽器獲取文件的過程以下:
Abigale's blog : Abigale's Blog