res.statusCode = 304;
複製代碼
當咱們在響應信息中回覆304時,瀏覽器會自動從本地的緩存數據庫中拿取數據。chrome
嗯,這句實際上是緩存中最關鍵的一句,其它的獲取設置緩存相關的頭都是再爲是否輸出這一句話作鋪墊。數據庫
res.setHeader('Expires',date.toUTCString());
res.setHeader('Cache-Control','max-age=10'); //以秒爲單位
複製代碼
Expires
和Cache-Control
都能起到強制緩存的做用,即在必定時間內客戶端的請求會先走本地緩存而不是向服務器發起。瀏覽器
其中Expires是http1.0
協議中的頭,咱們使用它通常都是爲了兼容,值得注意的是Expires的值和Cache-Control的值是不同的。緩存
Expires的值要求必須是GMT格式(?嗯,印象中有人這麼說過,反正我不用。。。),而Cache-Control值的格式則爲max-age=xxx
,xxx是一個數字,是一個相對時間,單位爲秒。bash
當Cache-Control
置爲no-cache
時,客戶端每次請求都會先忽略本地緩存直接向服務端詢問是否要採用緩存。服務器
又稱之爲「協商緩存」ui
根據文件的修改時間是否發生改變來決定是否採起緩存。spa
res.setHeader('Last-Modified',stat.ctime.toUTCSting());
複製代碼
let since = req.headers['if-modified-since'];
if(since){
if(since === stat.ctime.toUTCString()){ //沒有被修改
res.statusCode = 304; //讓它去緩存中找
res.end();
}else{
sendFile(req,res,p,stat);
}
}else{
sendFile(req,res,p,stat);
}
複製代碼
注意: 這個時間格式並無強制的限制,但咱們要注意在使用中要保持格式的一致。code
根據文件的內容是否發生改變來決定是否採起緩存。cdn
function sendFile(req,res,p,stat){
res.setHeader('Cache-Control','no-cache'); //不走本地緩存,會向服務器詢問
res.setHeader('Etag',r);
res.setHeader('Content-Type',mime.getType(p)+';charset=utf8');
...
}
複製代碼
...
let md5 = crypto.createHash('md5');
let rs = fs.createReadStream(p);
rs.on('data',function(data){
md5.update(data);
});
rs.on('end',function(){
let r = md5.digest('hex'); //對當前文件進行摘要
let ifNoneMatch = req.headers['if-none-match'];
if(ifNoneMatch){
if(ifNoneMatch===r){
res.statusCode = 304;
res.end();
}else{
sendFile(req,res,p,r);
}
}else{
sendFile(req,res,p,r);
}
})
...
複製代碼
若是文件過大時,進行摘要是很不實際的,So咱們通常選擇ctime+size做爲Etag
的值。
通常來講會同時使用上以上兩種緩存,這個時候會先看強制緩存是否過時,沒有過時就會從本地緩存中拿數據,只有過時了纔會向服務器詢問,這樣有利於減輕服務器的鴨梨。
Memory Cache 和 Disk Cache 是瀏覽器緩存的兩種模式。
筆者也不是很瞭解,這裏拋出只是爲了完善體系,這裏給出一些社區的回答
f5:跳過強制緩存,可是會檢查協商緩存
ctrl+f5:跳過強制緩存和協商緩存,服務器從新發送數據給瀏覽器