緩存正什,作為我們開發(fā)過程中經(jīng)常碰到的一樣?xùn)|西移剪,相信很多小伙伴和我一樣對它熟悉又陌生,各種 expires
瓤摧、Etag
好像都知道竿裂,卻又好像無法把它講清楚,所以本篇文章就來總結(jié)整理下照弥。
一腻异、緩存
首先,什么是緩存这揣?我的理解悔常,緩存就是一個資源副本。當我們向服務(wù)器請求資源后给赞,會根據(jù)情況將資源 copy 一份副本存在本地机打,以方便下次讀取。它與本地存儲 localStorage
片迅、cookie
等不同残邀,本地存儲更多是數(shù)據(jù)記錄,存儲量較小,為了本地操作方便芥挣。而緩存更多是為了減少資源請求驱闷,多用于存儲文件,存儲量相對較大空免。
那緩存有啥用呢空另?緩存最根本的作用就是減少沒必要請求。有些資源蹋砚,比如用戶頭像圖片扼菠,很久才改變一次,但每次都要去請求這張一樣的圖片坝咐,通信一來一回增加了頁面的顯示時長娇豫,過多沒必要請求也增加了服務(wù)器的壓力。如果把這張圖片直接緩存在本地畅厢,那每次就可以直接本地讀取加載,不再發(fā)起請求氮昧。所以緩存的好處也就顯而易見了框杜,減少了時長從而優(yōu)化用戶體驗,也減少了流量消耗袖肥,減輕了服務(wù)器的壓力咪辱。
那么,緩存有哪些呢椎组?就瀏覽器而言油狂,一般緩存我們分為四類,按瀏覽器讀取優(yōu)先級順序依次為:Memory Cache
寸癌、Service Worker Cache
专筷、HTTP Cache
、Push Cache
蒸苇。而本篇文章主要講的就是 HTTP Cache
磷蛹,其他有興趣可以自行搜索。
二溪烤、HTTP Cache
HTTP Cache
是我們開發(fā)中接觸最多的緩存味咳,它分為強緩存和協(xié)商緩存。
- 強緩存:直接從本地副本比對讀取檬嘀,不去請求服務(wù)器槽驶,返回的狀態(tài)碼是 200。
- 協(xié)商緩存:會去服務(wù)器比對鸳兽,若沒改變才直接讀取本地緩存掂铐,返回的狀態(tài)碼是 304。
(一)、強緩存
強緩存主要包括 expires
和 cache-control
堡纬。
1聂受、expires
expires
是 HTTP1.0
中定義的緩存字段。當我們請求一個資源烤镐,服務(wù)器返回時蛋济,可以在 Response Headers
中增加 expires
字段表示資源的過期時間。
expires: Thu, 03 Jan 2019 11:43:04 GMT
它是一個時間戳(準確點應(yīng)該叫格林尼治時間)炮叶,當客戶端再次請求該資源的時候碗旅,會把客戶端時間與該時間戳進行對比,如果大于該時間戳則已過期镜悉,否則直接使用該緩存資源祟辟。
但是,有個大問題侣肄,發(fā)送請求時是使用的客戶端時間去對比旧困。一是客戶端和服務(wù)端時間可能快慢不一致,另一方面是客戶端的時間是可以自行修改的(比如瀏覽器是跟隨系統(tǒng)時間的稼锅,修改系統(tǒng)時間會影響到)吼具,所以不一定滿足預(yù)期。
2矩距、cache-control
正由于上面說的可能存在的問題拗盒,HTTP1.1
新增了 cache-control
字段來解決該問題,所以當 cache-control
和 expires
都存在時锥债,cache-control
優(yōu)先級更高陡蝇。該字段是一個時間長度,單位秒哮肚,表示該資源過了多少秒后失效登夫。當客戶端請求資源的時候,發(fā)現(xiàn)該資源還在有效時間內(nèi)則使用該緩存允趟,它不依賴客戶端時間悼嫉。cache-control
主要有 max-age
和 s-maxage
、public
和 private
拼窥、no-cache
和 no-store
等值戏蔑。
cache-control: public, max-age=3600, s-maxage=3600
max-age
和s-maxage
兩者是cache-control
的主要字段,它們是一個數(shù)字鲁纠,表示資源過了多少秒之后變?yōu)闊o效总棵。在瀏覽器中,max-age
和s-maxage
都起作用改含,而且s-maxage
的優(yōu)先級高于max-age
情龄。在代理服務(wù)器中,只有s-maxage
起作用。 可以通過設(shè)置max-age
為 0 表示立馬過期來向服務(wù)器請求資源骤视。public
和private
public
表示該資源可以被所有客戶端和代理服務(wù)器緩存鞍爱,而private
表示該資源僅能客戶端緩存。默認值是private
专酗,當設(shè)置了s-maxage
的時候表示允許代理服務(wù)器緩存睹逃,相當于public
休偶。no-cache
和no-store
no-cache
表示的是不直接詢問瀏覽器緩存情況剃氧,而是去向服務(wù)器驗證當前資源是否更新(即協(xié)商緩存)黍少。no-store
則更狠路捧,完全不使用緩存策略,不緩存請求或響應(yīng)的任何內(nèi)容谎脯,直接向服務(wù)器請求最新丁寄。由于兩者都不考慮緩存情況而是直接與服務(wù)器交互喻圃,所以當no-cache
和no-store
存在時會直接忽略max-age
等蒋纬。
3猎荠、pragma
既然講到了 no-cache
和 no-store
,就順便把 pragma
也講了蜀备。他的值有 no-cache
和 no-store
关摇,表示意思同 cache-control
,優(yōu)先級高于 cache-control
和 expires
琼掠,即三者同時出現(xiàn)時,先看 pragma
-> cache-control
-> expires
停撞。
pragma: no-cache
(二)瓷蛙、協(xié)商緩存
上面的 expires
和 cache-control
都會訪問本地緩存直接驗證看是否過期,如果沒過期直接使用本地緩存戈毒,并返回 200艰猬。但如果設(shè)置了 no-cache
和 no-store
則本地緩存會被忽略,會去請求服務(wù)器驗證資源是否更新埋市,如果沒更新才繼續(xù)使用本地緩存冠桃,此時返回的是 304,這就是協(xié)商緩存道宅。協(xié)商緩存主要包括 last-modified
和 etag
食听。
1、last-modified
last-modified
記錄資源最后修改的時間污茵。啟用后樱报,請求資源之后的響應(yīng)頭會增加一個 last-modified
字段,如下:
last-modified: Thu, 20 Dec 2018 11:36:00 GMT
當再次請求該資源時泞当,請求頭中會帶有 if-modified-since
字段迹蛤,值是之前返回的 last-modified
的值,如:if-modified-since:Thu, 20 Dec 2018 11:36:00 GMT
。服務(wù)端會對比該字段和資源的最后修改時間盗飒,若一致則證明沒有被修改嚷量,告知瀏覽器可直接使用緩存并返回 304;若不一致則直接返回修改后的資源逆趣,并修改 last-modified
為新的值蝶溶。
但 last-modified
有以下兩個缺點:
- 只要編輯了,不管內(nèi)容是否真的有改變汗贫,都會以這最后修改的時間作為判斷依據(jù)身坐,當成新資源返回,從而導(dǎo)致了沒必要的請求響應(yīng)落包,而這正是緩存本來的作用即避免沒必要的請求部蛇。
- 時間的精確度只能到秒,如果在一秒內(nèi)的修改是檢測不到更新的咐蝇,仍會告知瀏覽器使用舊的緩存涯鲁。
2、etag
為了解決 last-modified
上述問題有序,有了 etag
抹腿。 etag
會基于資源的內(nèi)容編碼生成一串唯一的標識字符串,只要內(nèi)容不同旭寿,就會生成不同的 etag
警绩。啟用 etag
之后,請求資源后的響應(yīng)返回會增加一個 etag
字段盅称,如下:
etag: "FllOiaIvA1f-ftHGziLgMIMVkVw_"
當再次請求該資源時肩祥,請求頭會帶有 if-none-match
字段,值是之前返回的 etag
值缩膝,如:if-none-match:"FllOiaIvA1f-ftHGziLgMIMVkVw_"
混狠。服務(wù)端會根據(jù)該資源當前的內(nèi)容生成對應(yīng)的標識字符串和該字段進行對比,若一致則代表未改變可直接使用本地緩存并返回 304疾层;若不一致則返回新的資源(狀態(tài)碼200)并修改返回的 etag
字段為新的值将饺。
可以看出 etag
比 last-modified
更加精準地感知了變化,所以 etag
優(yōu)先級也更高痛黎。不過從上面也可以看出 etag
存在的問題予弧,就是每次生成標識字符串會增加服務(wù)器的開銷。所以要如何使用 last-modified
和 etag
還需要根據(jù)具體需求進行權(quán)衡湖饱。
三桌肴、訪問刷新分析
我們將訪問和刷新分為以下三種情況:
- 標簽進入、輸入url回車進入
- 按刷新按鈕琉历、F5 刷新坠七、網(wǎng)頁右鍵“重新加載”
- ctrl + F5 強制刷新
假設(shè)當前有這么一個 index 頁面水醋,返回的響應(yīng)信息如下:
cache-control: max-age=72000
expires: Tue, 20 Nov 2018 20:41:14 GMT
last-modified: Tue, 20 Nov 2018 00:41:14 GMT
1、標簽進入彪置、輸入url回車進入
這種情況下會根據(jù)實際設(shè)計的緩存策略去判斷拄踪。
- 由于該例沒有設(shè)置
no-cache
和no-store
,所以默認先走強緩存路線拳魁。根據(jù)cache-control
(expires
優(yōu)先級低)判斷緩存是否過期惶桐,若沒有過期則此時返回200(from cache)
。 - 若本地緩存已經(jīng)過期再走協(xié)商緩存路線潘懊,根據(jù)之前的
last-modified
值去與服務(wù)器比對姚糊,若這個時間之后沒有改過則去讀取本地緩存,返回304(not modified)
授舟。 - 否則返回新的資源救恨,狀態(tài)碼
200(ok)
,并更新返回響應(yīng)的last-modified
值释树。
2肠槽、按刷新按鈕、F5 刷新奢啥、網(wǎng)頁右鍵“重新加載”
這種情況下秸仙,實際是瀏覽器將 cache-control
的 max-age
直接設(shè)置成了 0,讓緩存立即過期桩盲,直接走協(xié)商緩存路線寂纪。發(fā)送的請求頭如下:
cache-control: max-age=0
if-modified-since: Tue, 20 Nov 2018 00:41:14 GMT
3、ctrl + F5 強制刷新
強制刷新的情況下赌结,瀏覽器會強行設(shè)置 no-cache
捞蛋,強制獲取最新的資源,就連 if-modified-since
等其他緩存協(xié)議字段都會被吃掉姑曙。此時發(fā)送的請求頭如下:
cache-control: no-cache
pragma: no-cache
參考文章: