本文作者:IMWeb 存勖閑 原文出處:IMWeb社區(qū)
原文鏈接:http://www.cun-xu.cn/index.php/2018/12/26/瀏覽器緩存/
今天我們來說一下瀏覽器緩存的問題,緩存可以減少網(wǎng)絡(luò)IO的消耗,提高訪問速度。瀏覽器緩存是一種操作簡單、效果顯著的前端性能優(yōu)化手段。
關(guān)于緩存的頭部字段包括:
每個資源都可通過cache-control
HTTP標頭定義其緩存策略
cache-control
指令控制誰在什么條件下可以緩存響應(yīng)以及可以緩存多少
public
:即使它有相關(guān)聯(lián)的http身份驗證,甚至響應(yīng)狀態(tài)代碼通常無法緩存,也可以緩存響應(yīng)。大多數(shù)情況下,public
不是必需的,因為明確的緩存信息(例如max-age
)已表示響應(yīng)是可以緩存的。
private
:瀏覽器可以緩存private
響應(yīng)。不過,這些響應(yīng)通常只為單個用戶緩存,因此不允許任何中間緩存對其進行緩存。例如,用戶的瀏覽器可以緩存包含私人信息的HTML網(wǎng)頁,但CDN卻不能進行緩存。
no-cache
:表示必須先與服務(wù)器確認返回的響應(yīng)是否發(fā)生了變化,然后才能使用該響應(yīng)來滿足后續(xù)對同一網(wǎng)址的請求。因此,如果存在合適的驗證令牌(Etag
),no-cache
會發(fā)起往返通信來驗證緩存的響應(yīng),但如果資源未發(fā)生變化,則可避免下載。有的時候只設(shè)置no-cache
防止緩存還是不夠保險,還可以加上private
指令,將過期時間設(shè)為過去的時間。
max-age=(seconds
)指令指定從請求的時間開始,允許獲取的響應(yīng)被重用的最長時間(單位:秒)。例如,"max-age=60
"表示可在接下來的60秒緩存和重用響應(yīng)。
s-maxage=(seconds
):同max-age
,只用于共享緩存(比如CDN緩存)比如,當s-maxage=60
時,在這60秒鐘,即使更新了CDN的內(nèi)容,瀏覽器也不會進行請求。也就是說max-age用與普通緩存,而s-maxage
用于代理緩存,如果存在s-maxage
,則會覆蓋掉max-age
和Expires
header。
max-stale=(seconds
)為發(fā)起端設(shè)置,即使緩存已經(jīng)到期,但在max-stale
設(shè)置的時間內(nèi)還可以使用過期的緩存。
must-revalidate
緩存必須在使用之前驗證舊資源的狀態(tài),并且不可使用過期資源。
proxy-revalidate
與must-revalidate
作用相同,但它僅適用于共享緩存(例如代理),并被私有緩存忽略。
no-store
直接禁止瀏覽器以及所有中間緩存存儲任何版本的返回響應(yīng),例如,包含個人隱私數(shù)據(jù)或銀行業(yè)務(wù)數(shù)據(jù)的響應(yīng)。每次用戶請求該資源時,都會向服務(wù)器發(fā)送請求,并下載完整的響應(yīng)。
no-transform
不得對資源進行轉(zhuǎn)換或轉(zhuǎn)變。Content-Encoding, Content-Range, Content-Type等HTTP頭不能由代理修改。例如,非透明代理可以對圖像格式進行轉(zhuǎn)換,以便節(jié)省緩存空間或者減少緩慢鏈路上的流量。 no-transform指令不允許這樣做。
當該字段值為no-cache
的時候。會告訴瀏覽器不要對該資源緩存,及每一次都得向服務(wù)器發(fā)送一次響應(yīng)。
res.serHeader('Pragma','no-cache') //禁止緩存res.setHeader('Cache-Control','public,max-age=120') //2分鐘
通過Pragma
來禁止緩存,通過Cache-Control
設(shè)置兩分鐘緩存,但是重新訪問我們會發(fā)現(xiàn)瀏覽器會再次發(fā)起一次請求,說明了Pragma的優(yōu)先級高于Cache-Control
。
緩存過期時間,用來指定資源到期的時間,是服務(wù)器端的具體的時間點。也就是說,Expires = max-age + 請求時間
,需要和Last-modified
結(jié)合使用。但在上面我們提到過,cache-control
的優(yōu)先級更高。Expires是Web服務(wù)器響應(yīng)消息頭字段,在響應(yīng)http請求時告訴瀏覽器在過期時間前可以直接從瀏覽器緩存取數(shù)據(jù),而無需再次請求。
服務(wù)器端文件的最后修改時間,需要和catch-control
共同使用,是檢查服務(wù)器資源是否更新的一種方式。當瀏覽器再次進行請求時,會向服務(wù)器傳送If-Modified-Since
報頭,詢問Last-Modified
時間點之后資源是否被修改過。如果沒有修改,則返回碼為304,使用緩存;如果修改過,則再次去服務(wù)器請求資源,返回碼和首次請求相同為200,資源為服務(wù)器最新資源。
根據(jù)試題內(nèi)容生成一段哈希字符串,標識資源的狀態(tài),由服務(wù)器產(chǎn)生。瀏覽器會將這串字符串傳回服務(wù)器,驗證資源是否已被修改,如果沒有修改,過程如下:
某些服務(wù)器不能精確得到資源的最后修改時間,這樣就無法通過最后修改時間判斷資源是否更新
如果某些資源修改非常頻繁,在秒一下的時間內(nèi)進行修改,而last-modified
只能精確到秒。
一些資源的最后修改時間改變了,但是內(nèi)容沒改變,使用Etag
就認為資源還是沒有修改的
根據(jù)查到的資料顯示,緩存頭的優(yōu)先級是這樣的:
Pragma > Cache-Control > Expires > Etag > Last-Modified
至于緩存策略的制定,我們可以參照Google官方的這張圖
由于圖上都是英文,我猜像我這樣的菜鳥都看不懂,這里借資料來解釋一下:
當我們的資源內(nèi)容不可復(fù)用時,直接為
Cache-Control
設(shè)置no-store
,拒絕一切形式的緩存;否則考慮是否每次都需要向服務(wù)器進行緩存有效確認,如果需要,那么設(shè)Cache-Control
的值為no-cach
e;否則考慮該資源是否可以被代理服務(wù)器緩存,根據(jù)其結(jié)果決定是設(shè)置為private
還是public
;然后考慮該資源的過期時間,設(shè)置對應(yīng)的max-age
和s-maxage
值;最后,配置協(xié)商緩存需要用到的Etag、Last-Modified
等參數(shù)。
根據(jù)上面的基礎(chǔ)知識和解讀,我們可以知曉:在制定緩存策略時,需要牢記以下技巧:
使用一致的網(wǎng)址:如果您在不同的網(wǎng)址上提供相同的內(nèi)容,將會多次獲取和存儲這些內(nèi)容。提示:網(wǎng)址區(qū)分大小寫。
確保服務(wù)器提供驗證令牌(Etag
):有了驗證令牌,當服務(wù)器上的資源未發(fā)生變化時,就不需要傳送相同的字節(jié)。
確定中間緩存可以緩存哪些資源:對所有用戶的響應(yīng)完全相同的資源非常適合由CDN以及其他中間緩存進行緩存。
為每個資源確定最佳緩存周期:不同的資源可能有不同的更新要求。為每個資源審核并確定合適的max-age
。
確定最合適您的網(wǎng)站的緩存層次結(jié)構(gòu):您可以通過為HTML文檔組合使用包含內(nèi)容指紋的資源網(wǎng)址和短時間或no-cache
周期,來控制客戶端獲取更新的速度。
最大限度減少攪動:某些資源的更新比其他資源頻繁。如果資源的特定部分(例如JavaScript函數(shù)或CSS樣式集)會經(jīng)常更新,可以考慮將其代碼作為單獨的文件提供。這樣一來,每次獲取更新時,其余內(nèi)容(例如變化不是很頻繁的內(nèi)容庫代碼)可以從緩存獲取,從而最大限度減少下載的內(nèi)容大小
文章的最后我們還要說一下內(nèi)存緩存(from memory cache
)和硬盤緩存(from disk cache
)。
內(nèi)存緩存有兩個特點,分別是快速讀取和時效性。
快速讀?。簝?nèi)存換粗會將編譯解析后的文件,直接存入該進程的內(nèi)存中,占據(jù)該進程一定的內(nèi)存資源,以便下次運行時的快速讀取
時效性:一旦該進程關(guān)閉,則該進程的內(nèi)存會被清空
硬盤緩存- 則是將緩存直接寫入硬盤文件中,讀取緩存需要對該緩存存放的硬盤文件進行I/O操作,然后重新解析該緩存內(nèi)容,讀取復(fù)雜,速度比內(nèi)存緩存慢。
那么哪些文件會被放入內(nèi)存中呢?
事實上,這個劃分規(guī)則,一直以來是沒有定論的。不過想想也可以理解,內(nèi)存時有限的,很多時候需要先考慮即時呈現(xiàn)的內(nèi)存余量,再根據(jù)具體的情況決定分配給內(nèi)存和磁盤的資源量的比重——資源存放的位置具有一定的隨機性。
雖然劃分規(guī)則沒有定論,但根據(jù)日常開發(fā)中觀察的結(jié)果,我們至少可以總結(jié)出這樣的規(guī)律:資源存不存內(nèi)存,瀏覽器秉承的是“節(jié)約原則”。我們發(fā)現(xiàn),Base64格式的圖片,幾乎永遠可以被塞進memory cache,這可以視作瀏覽器為節(jié)省渲染開銷的“自保行為”;此外,體積不大的 JS、CSS 文件,也有較大地被寫入內(nèi)存的幾率——相比之下,較大的 JS、CSS 文件就沒有這個待遇了,內(nèi)存資源是有限的,它們往往被直接甩進磁盤。
瀏覽器讀取緩存的順序為memory –> disk
好啦,著急忙慌整完了,正好零點,碎覺碎覺。明天還要考試,關(guān)老爺保佑?。?!
參考文章:https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching?hl=zh-cn http://www.alloyteam.com/2016/03/discussion-on-web-caching/#prettyPhoto