http緩存:
Web 緩存是可以自動(dòng)保存常見文檔副本的 HTTP 設(shè)備。當(dāng) Web 請(qǐng)求抵達(dá)緩存時(shí), 如果本地有“已緩存的”副本,就可以從本地存儲(chǔ)設(shè)備而不是原始服務(wù)器中提取這 個(gè)文檔。
使用緩存主要有如下幾個(gè)優(yōu)點(diǎn):
- 緩存減少了冗余的數(shù)據(jù)傳輸,節(jié)省了你的網(wǎng)絡(luò)費(fèi)用。
- 緩存緩解了網(wǎng)絡(luò)瓶頸問題。不需要更多的帶寬就能夠更快的加載頁面。
- 緩存降低了對(duì)原始服務(wù)器的要求。服務(wù)器可以更快地響應(yīng),避免過載的出現(xiàn)。
- 緩存降低了距離時(shí)延,因?yàn)閺妮^遠(yuǎn)的地方加載頁面會(huì)更慢一些。
緩存的處理步驟:
一個(gè)緩存從接收到請(qǐng)求到做出響應(yīng),大概可以分為如下7個(gè)步驟:
- 接收——緩存從網(wǎng)絡(luò)中讀取抵達(dá)的請(qǐng)求報(bào)文。
- 解析——緩存對(duì)報(bào)文進(jìn)行解析,提取出URL和各種首部。
- 查詢——緩存查看是否有本地副本可用,如果沒有,就獲取一份副本(并將其保存在本地)。
- 新鮮度檢測——緩存查看已緩存副本是否足夠新鮮,如果不是,就詢問服務(wù)器是否有任何更新。
- 創(chuàng)建響應(yīng)——緩存會(huì)用新的首部和已緩存的主體來構(gòu)建一條響應(yīng)報(bào)文。
- 發(fā)送——緩存通過網(wǎng)絡(luò)將響應(yīng)發(fā)回給客戶端。
- 日志——緩存可選地創(chuàng)建一個(gè)日志文件條目來描述這個(gè)事務(wù)。
Http緩存流程圖:
狀態(tài)碼區(qū)別:
- 200 請(qǐng)求成功,服務(wù)器返回全新的數(shù)據(jù)
- 200 from memory cache / from disk cache 本地強(qiáng)緩存還在有效期,直接使用本地緩存
- 304 請(qǐng)求成功,走了協(xié)商緩存,服務(wù)器判定(Etag和Last-modified)沒有過期,告知瀏覽器使用緩存
業(yè)務(wù)中的使用場景:
項(xiàng)目中,我們主要使用緩存來存儲(chǔ)html、css、js、img等靜態(tài)資源,一般不會(huì)去存儲(chǔ)動(dòng)態(tài)資源,因?yàn)閷?duì)動(dòng)態(tài)資源的緩存會(huì)對(duì)數(shù)據(jù)實(shí)時(shí)性造成影響
1、強(qiáng)制緩存
強(qiáng)緩存是當(dāng)我們?cè)L問URL的時(shí)候,不會(huì)向服務(wù)器發(fā)送請(qǐng)求,直接從緩存中讀取資源,但是會(huì)返回200的狀態(tài)碼。
我們第一次進(jìn)入頁面,請(qǐng)求服務(wù)器,然后服務(wù)器進(jìn)行應(yīng)答,瀏覽器會(huì)根據(jù)response Header來判斷是否對(duì)資源進(jìn)行緩存,如果響應(yīng)頭中expires、pragma或者cache-control字段,代表這是強(qiáng)緩存,瀏覽器就會(huì)把資源緩存在memory cache 或 disk cache中。
第二次請(qǐng)求時(shí),瀏覽器判斷請(qǐng)求參數(shù),如果符合強(qiáng)緩存條件就直接返回狀態(tài)碼200,從本地緩存中拿數(shù)據(jù)。否則把響應(yīng)參數(shù)存在request header請(qǐng)求頭中,看是否符合協(xié)商緩存,符合則返回狀態(tài)碼304,不符合則服務(wù)器會(huì)返回全新資源。
Expires:
這是 http1.0 時(shí)的規(guī)范;它的值為一個(gè)絕對(duì)時(shí)間的GMT格式的時(shí)間字符串,如Mon, 10 Jun 2022 21: 31 :12 GMT,如果發(fā)送請(qǐng)求的時(shí)間在expires之前,那么本地緩存始終有效,否則就會(huì)發(fā)送請(qǐng)求到服務(wù)器來獲取資源。
Expires過度依賴本地時(shí)間,如果本地與服務(wù)器時(shí)間不同步,就會(huì)出現(xiàn)資源無法被緩存或者資源永遠(yuǎn)被緩存的情況。所以,Expires字段幾乎不被使用了
cache-control:
上面我們提到了Expires有個(gè)缺點(diǎn),當(dāng)客戶端本地時(shí)間和服務(wù)器時(shí)間不一致時(shí)會(huì)產(chǎn)生誤差,瀏覽器會(huì)直接向服務(wù)器請(qǐng)求新的資源,為了解決這個(gè)問題,在http1.1規(guī)范中,提出了cache-control字段,且這個(gè)字段優(yōu)先級(jí)高于上面提到的Expires,值是相對(duì)時(shí)間。
在cache-control中有常見的幾個(gè)響應(yīng)屬性值,它們分別是:
- max-age=100 緩存100秒后過期,資源緩存在本地
- s-maxage 覆蓋 max-age,作用與max-age一樣,但只用于代理服務(wù)器中緩存
- no-cache 不使用本地緩存。使用協(xié)商緩存,先與服務(wù)器確認(rèn)返回的響應(yīng)是否被更改,如果之前的響應(yīng)中存在ETag,那么請(qǐng)求的時(shí)候會(huì)與服務(wù)端驗(yàn)證,如果資源未被更改,則可以避免重新下載。
- no-store 所有內(nèi)容都不會(huì)被緩存,既不使用強(qiáng)制緩存也不適用協(xié)商緩存,每次用戶請(qǐng)求該資源,都會(huì)向服務(wù)器發(fā)送一個(gè)請(qǐng)求,服務(wù)器再返回資源
- public 可以被所有的用戶緩存,包括客戶端和代理服務(wù)器
- private 只能被客戶端緩存,不允許CDN等中繼緩存服務(wù)器對(duì)其緩存
2、協(xié)商緩存
上面提到的強(qiáng)緩存都是由本地瀏覽器在確定是否使用緩存,當(dāng)瀏覽器沒有命中強(qiáng)緩存時(shí)就會(huì)向?yàn)g覽器發(fā)送請(qǐng)求,驗(yàn)證協(xié)商緩存是否命中,如果緩存命中則返回304狀態(tài)碼,否則返回新的資源數(shù)據(jù)。
協(xié)商緩存(也叫對(duì)比緩存)是由服務(wù)器來確定資源是否可用,這將涉及到兩組字段成對(duì)出現(xiàn)的,在瀏覽器第一次發(fā)出請(qǐng)求時(shí)會(huì)帶上字段(Last-Modified或者Etag),則后續(xù)請(qǐng)求則會(huì)帶上對(duì)于的請(qǐng)求字段(if-modified-since或者if-none-Match),若響應(yīng)頭沒有Last-Modified或者Etag,則請(qǐng)求頭也不會(huì)有對(duì)應(yīng)的字段
基于Last-Modified:
- 首先需要在服務(wù)器端讀出文件修改時(shí)間,
- 將讀出來的修改時(shí)間賦給響應(yīng)頭的last-modified字段。
- 最后設(shè)置Cache-control:no-cache
const http = require('http');
const fs = require('fs');
http.createServer((req,res)=>{
if(req.url === 'test.png'){
const data = fs.readFileSync('./test.png');
const {mtime} = fs.statSync('./test.png');
const temp = req.headers['if-modified-since'];
if(temp === mtime.toUTCString()){
res.statusCode = 304;
res.end();
return;
}
res.setHeader('last-modified',mtime.toUTCString());
res.setHeader('Catch-Control','no=cache');
res.end(data);
}else{
res.end(fs.readFileSync('./test.html'));
}
})
基于ETag:
- 第一次請(qǐng)求某資源的時(shí)候,服務(wù)端讀取文件并計(jì)算出文件指紋,將文件指紋放在響應(yīng)頭的etag字段中跟資源一起返回給客戶端。
- 第二次請(qǐng)求某資源的時(shí)候,客戶端自動(dòng)從緩存中讀取出上一次服務(wù)端返回的ETag也就是文件指紋。并賦給請(qǐng)求頭的if-None-Match字段,讓上一次的文件指紋跟隨請(qǐng)求一起回到服務(wù)端。
- 服務(wù)端拿到請(qǐng)求頭中的is-None-Match字段值(也就是上一次的文件指紋),并再次讀取目標(biāo)資源并生成文件指紋,兩個(gè)指紋做對(duì)比。如果兩個(gè)文件指紋完全吻合,說明文件沒有被改變,則直接返回304狀態(tài)碼和一個(gè)空的響應(yīng)體并return。如果兩個(gè)文件指紋不吻合,則說明文件被更改,那么將新的文件指紋重新存儲(chǔ)到響應(yīng)頭的ETag中并返回給客戶端
const http = require('http');
const fs = require('fs');
const etag = require('etag');
http.createServer((req,res)=>{
if(req.url === 'test.png'){
const data = fs.readFileSync('./test.png');
const etagContent = etag(data);
const noMatch = req.headers['if-none-match'];
if(noMatch === etagContent){
res.statusCode = 304;
res.end();
return;
}
res.setHeader('etag',etagContent);
res.setHeader('Catch-Control','no=cache');
res.end(data);
}else{
res.end(fs.readFileSync('./test.html'));
}
})
作者簡介
畢清華:精選主力干將!
來源:微信公眾號(hào):58本地服務(wù)終端技術(shù)
出處
:https://mp.weixin.qq.com/s/-83N7RS1B6V_r5tcU2CyrA