在前端開發中,性能一直都是被你們所重視的一點,然而判斷一個網站的性能最直觀的就是看網頁打開的速度。其中提升網頁反應速度的一個方式就是使用緩存。一個優秀的緩存策略能夠縮短網頁請求資源的距離,減小延遲,而且因爲緩存文件能夠重複利用,還能夠減小帶寬,下降網絡負荷。前端
由此可知:git
一、強制緩存階段:先在本地查找該資源,若是有發現該資源,並且該資源尚未過時,就使用這一個資源,徹底不會發送http請求到服務器github
二、協商緩存階段:若是在本地緩存找到對應的資源,可是不知道該資源是否過時或者已通過期,則發一個http請求到服務器,而後服務器判斷這個請求,若是請求的資源在服務器上沒有改動過,則返回304,讓瀏覽器使用本地找到的那個資源;web
三、啓發式緩存階段算法
四、緩存失敗階段:當服務器發現請求的資源已經修改過,或者這是一個新的請求(在原本沒有找到資源),服務器則返回該資源的數據,而且返回200, 固然這個是指找到資源的狀況下,若是服務器上沒有這個資源,則返回404。瀏覽器
由上面能夠知道強制緩存是直接使用本地的緩存,不發送http請求,那麼判斷它是否要進行強制緩存的標誌是什麼呢?緩存
Expires是HTTP/1.0控制網頁緩存的字段,其值爲服務器返回該請求結果緩存的到期時間(絕對時間),即再次發起該請求時,若是客戶端的當前時間小於Expires的值時,直接使用緩存結果。服務器
缺點:由於是絕對時間,若是客戶端與服務端的時間由於某些緣由(例如時區不一樣;客戶端和服務端有一方的時間不許確)發生偏差,強緩存可能直接失效。cookie
app.get('/1.jpg',function(req,res,next){
...
res.setHeader('Expires', new Date(Date.now() + 10 * 1000).toUTCString())
})
複製代碼
在HTTP/1.1中,Cache-Control是最重要的規則,主要用於控制網頁緩存,它有幾個選項: 一、public : 全部的內容都被緩存(客戶端和代理服務器均可緩存) 二、private : 全部的內容都被緩存(客戶端緩存,cache-control的默認值) 三、no-cache: 客戶端緩存,可是是否使用緩存得經過協商緩存來決定 四、no-store: 全部內容都不緩存,既不強制緩存,又不協商緩存 五、max-age=num(num的單位是秒) : 緩存內容在num秒後失效,num爲相對時間網絡
app.get('/2.jpg',function(req,res,next){
res.setHeader('Expires', new Date(Date.now() + 10 * 1000).toUTCString())
res.setHeader('Cache-Control', 'max-age=20')
...
})
複製代碼
通過強緩存後,客戶端再請求,若是緩存標誌有效,則返回灰色200,數據從瀏覽器緩存中取出。 優先級:Cache-Control > expires
當緩存過時時間的字段一個都沒有的時候,瀏覽器下次並不會直接進入協商階段,而是先進入啓發式緩存階段,你能夠經過關閉服務器,刷新頁面來觀察。 它根據響應頭中2個時間字段 Date 和 Last-Modified 之間的時間差值,取其值的10%做爲緩存時間週期。 也就是說,當存有 Last-Modified字段的時候,即便是斷網,且強緩存都失效後,也有必定時間是直接讀取緩存文件的。 etag是沒有這個階段的。
協商階段就是當強緩存階段失效的時候,http請求會攜帶緩存標誌符向服務器發起請求,由服務器來決定是否使用緩存,瀏覽器根據返回到code碼來決定是否從瀏覽器緩存中拿去數據。
Last-Modified是服務器響應請求時,返回該資源文件在服務器最後被修改的時間。 If-Modified-Since是再次請求該資源文件的時候,會帶上上次請求中的Last-Modified時間,服務器經過對比Last-Modified / If-Modified-Since,返回200,則有更新,從服務器拉取數據,304則使用緩存文件
app.get('/3.jpg',function(req,res,next){
...
let ifModifiedSince = req.headers['if-modified-since']
let LastModified = stat.ctime.toGMTString()
if(!!ifModifiedSince && LastModified === ifModifiedSince){
res.statusCode = 304
res.end()
}
if(!ifModifiedSince || (!!ifModifiedSince && LastModified !== ifModifiedSince)){
res.setHeader('Last-Modified', LastModified)
}
...
})
})
複製代碼
Etag是服務器響應請求時,返回當前資源文件的一個惟一標識(由服務器根據文件信息算法生成,相似hash) If-None-Match是客戶端再次發起該請求時,攜帶上次請求返回的惟一標識Etag值,經過此字段值告訴服務器該資源上次請求返回的惟一標識值。服務器收到該請求後,發現該請求頭中含有If-None-Match,則會根據If-None-Match的字段值與該資源在服務器的Etag值作對比,一致則返回304,表明資源無更新,繼續使用緩存文件;不一致則從新返回資源文件,狀態碼爲200
app.get('/4.jpg',function(req,res,next){
reponseHandle(req,res,(stat)=>{
let ifNoneMatch = req.headers['if-none-match']
let etag = .....
if(!ifNoneMatch || (!!ifNoneMatch && ifNoneMatch!== etag)){
res.setHeader('ETag', etag)
}
if(!!ifNoneMatch && ifNoneMatch === etag){
res.statusCode = 304
res.end()
}
})
})
複製代碼
Etag / If-None-Match優先級高於Last-Modified / If-Modified-Since,同時存在則只有Etag / If-None-Match生效
因而可知,強制緩存優先於協商緩存進行,若強制緩存(Expires和Cache-Control)生效則直接使用緩存,若不生效則進行協商緩存(Last-Modified / If-Modified-Since和Etag / If-None-Match),協商緩存由服務器決定是否使用緩存,若協商緩存失效,那麼表明該請求的緩存失效,從新獲取請求結果,再存入瀏覽器緩存中;生效則返回304,繼續使用緩存
字段 | 說明 |
---|---|
pragma | http1.0,值爲no-cache爲禁用緩存 |
vary | 基於字段區分緩存版本(res header) |
Date | 發送響應報文的時間(啓發式緩存、代理服務器緩存) |
Age | 文件存於服務器的時間 |
accept-encoding | 請求服務器返回的文件類型 |
referer | 發送請求的源域名 |
CDN緩存,也叫網關緩存、反向代理緩存。瀏覽器先向CDN網關發起WEB請求,網關服務器後面對應着一臺或多臺負載均衡源服務器,會根據它們的負載請求,動態地請求轉發到合適的源服務器上。
CDN的優點:
由於幾個歷史緣由,app cache已經不推薦使用,從web標準移除了。緣由以下:
Service workers 本質上充當Web應用程序與瀏覽器之間的代理服務器,也能夠在網絡可用時做爲瀏覽器和網絡間的代理。它們旨在(除其餘以外)使得可以建立有效的離線體驗,攔截網絡請求並基於網絡是否可用以及更新的資源是否駐留在服務器上來採起適當的動做。他們還容許訪問推送通知和後臺同步API。
service worker的特色:
具體請移步
key | value |
---|---|
expires | Cookie失效時間(絕對時間)若不設置,瀏覽器關閉即刪除 |
Max-Age | Cookie失效時間,相對時間,優先級高於expires |
path | 設置哪些路徑帶上cookie,通常默認爲'/' |
Domain | 設置哪些域名帶上cookie,通常爲當前一級域名 |
Secure | 只在https下才能發送cookie |
HttpOnly | js腳本獲取不到,且只能在http上才能發送cookie(防止xss) |
SameSite | 是否可能做爲第三方 cookie(防止CSRF) |
相同點
不一樣點
推薦一下本身的我的公衆號:前端精讀(每日定時推送一篇前端好文)