本文作者:IMWeb 存勖閑 原文出處:IMWeb社區
原文鏈接:http://www.cun-xu.cn/index.php/2018/12/26/瀏覽器緩存/
今天我們來(lái)說(shuō)一下瀏覽器緩存的問(wèn)題,緩存可以減少網(wǎng)絡(luò )IO的消耗,提高訪(fǎng)問(wèn)速度。瀏覽器緩存是一種操作簡(jiǎn)單、效果顯著(zhù)的前端性能優(yōu)化手段。
關(guān)于緩存的頭部字段包括:
每個(gè)資源都可通過(guò)cache-controlHTTP標頭定義其緩存策略
cache-control指令控制誰(shuí)在什么條件下可以緩存響應以及可以緩存多少
public:即使它有相關(guān)聯(lián)的http身份驗證,甚至響應狀態(tài)代碼通常無(wú)法緩存,也可以緩存響應。大多數情況下,public不是必需的,因為明確的緩存信息(例如max-age)已表示響應是可以緩存的。
private:瀏覽器可以緩存private響應。不過(guò),這些響應通常只為單個(gè)用戶(hù)緩存,因此不允許任何中間緩存對其進(jìn)行緩存。例如,用戶(hù)的瀏覽器可以緩存包含私人信息的HTML網(wǎng)頁(yè),但CDN卻不能進(jìn)行緩存。
no-cache:表示必須先與服務(wù)器確認返回的響應是否發(fā)生了變化,然后才能使用該響應來(lái)滿(mǎn)足后續對同一網(wǎng)址的請求。因此,如果存在合適的驗證令牌(Etag),no-cache會(huì )發(fā)起往返通信來(lái)驗證緩存的響應,但如果資源未發(fā)生變化,則可避免下載。有的時(shí)候只設置no-cache防止緩存還是不夠保險,還可以加上private指令,將過(guò)期時(shí)間設為過(guò)去的時(shí)間。
max-age=(seconds)指令指定從請求的時(shí)間開(kāi)始,允許獲取的響應被重用的最長(cháng)時(shí)間(單位:秒)。例如,"max-age=60"表示可在接下來(lái)的60秒緩存和重用響應。
s-maxage=(seconds):同max-age,只用于共享緩存(比如CDN緩存)比如,當s-maxage=60時(shí),在這60秒鐘,即使更新了CDN的內容,瀏覽器也不會(huì )進(jìn)行請求。也就是說(shuō)max-age用與普通緩存,而s-maxage用于代理緩存,如果存在s-maxage,則會(huì )覆蓋掉max-age和Expiresheader。
max-stale=(seconds)為發(fā)起端設置,即使緩存已經(jīng)到期,但在max-stale設置的時(shí)間內還可以使用過(guò)期的緩存。
must-revalidate緩存必須在使用之前驗證舊資源的狀態(tài),并且不可使用過(guò)期資源。
proxy-revalidate與must-revalidate作用相同,但它僅適用于共享緩存(例如代理),并被私有緩存忽略。
no-store直接禁止瀏覽器以及所有中間緩存存儲任何版本的返回響應,例如,包含個(gè)人隱私數據或銀行業(yè)務(wù)數據的響應。每次用戶(hù)請求該資源時(shí),都會(huì )向服務(wù)器發(fā)送請求,并下載完整的響應。
no-transform不得對資源進(jìn)行轉換或轉變。Content-Encoding, Content-Range, Content-Type等HTTP頭不能由代理修改。例如,非透明代理可以對圖像格式進(jìn)行轉換,以便節省緩存空間或者減少緩慢鏈路上的流量。 no-transform指令不允許這樣做。
當該字段值為no-cache的時(shí)候。會(huì )告訴瀏覽器不要對該資源緩存,及每一次都得向服務(wù)器發(fā)送一次響應。
res.serHeader('Pragma','no-cache') //禁止緩存res.setHeader('Cache-Control','public,max-age=120') //2分鐘通過(guò)Pragma來(lái)禁止緩存,通過(guò)Cache-Control設置兩分鐘緩存,但是重新訪(fǎng)問(wèn)我們會(huì )發(fā)現瀏覽器會(huì )再次發(fā)起一次請求,說(shuō)明了Pragma的優(yōu)先級高于Cache-Control。
緩存過(guò)期時(shí)間,用來(lái)指定資源到期的時(shí)間,是服務(wù)器端的具體的時(shí)間點(diǎn)。也就是說(shuō),Expires = max-age + 請求時(shí)間,需要和Last-modified結合使用。但在上面我們提到過(guò),cache-control的優(yōu)先級更高。Expires是Web服務(wù)器響應消息頭字段,在響應http請求時(shí)告訴瀏覽器在過(guò)期時(shí)間前可以直接從瀏覽器緩存取數據,而無(wú)需再次請求。
服務(wù)器端文件的最后修改時(shí)間,需要和catch-control共同使用,是檢查服務(wù)器資源是否更新的一種方式。當瀏覽器再次進(jìn)行請求時(shí),會(huì )向服務(wù)器傳送If-Modified-Since報頭,詢(xún)問(wèn)Last-Modified時(shí)間點(diǎn)之后資源是否被修改過(guò)。如果沒(méi)有修改,則返回碼為304,使用緩存;如果修改過(guò),則再次去服務(wù)器請求資源,返回碼和首次請求相同為200,資源為服務(wù)器最新資源。
根據試題內容生成一段哈希字符串,標識資源的狀態(tài),由服務(wù)器產(chǎn)生。瀏覽器會(huì )將這串字符串傳回服務(wù)器,驗證資源是否已被修改,如果沒(méi)有修改,過(guò)程如下:

某些服務(wù)器不能精確得到資源的最后修改時(shí)間,這樣就無(wú)法通過(guò)最后修改時(shí)間判斷資源是否更新
如果某些資源修改非常頻繁,在秒一下的時(shí)間內進(jìn)行修改,而last-modified只能精確到秒。
一些資源的最后修改時(shí)間改變了,但是內容沒(méi)改變,使用Etag就認為資源還是沒(méi)有修改的
根據查到的資料顯示,緩存頭的優(yōu)先級是這樣的:
Pragma > Cache-Control > Expires > Etag > Last-Modified至于緩存策略的制定,我們可以參照Google官方的這張圖
由于圖上都是英文,我猜像我這樣的菜鳥(niǎo)都看不懂,這里借資料來(lái)解釋一下:
當我們的資源內容不可復用時(shí),直接為
Cache-Control設置no-store,拒絕一切形式的緩存;否則考慮是否每次都需要向服務(wù)器進(jìn)行緩存有效確認,如果需要,那么設Cache-Control的值為no-cache;否則考慮該資源是否可以被代理服務(wù)器緩存,根據其結果決定是設置為private還是public;然后考慮該資源的過(guò)期時(shí)間,設置對應的max-age和s-maxage值;最后,配置協(xié)商緩存需要用到的Etag、Last-Modified等參數。
根據上面的基礎知識和解讀,我們可以知曉:在制定緩存策略時(shí),需要牢記以下技巧:
使用一致的網(wǎng)址:如果您在不同的網(wǎng)址上提供相同的內容,將會(huì )多次獲取和存儲這些內容。提示:網(wǎng)址區分大小寫(xiě)。
確保服務(wù)器提供驗證令牌(Etag):有了驗證令牌,當服務(wù)器上的資源未發(fā)生變化時(shí),就不需要傳送相同的字節。
確定中間緩存可以緩存哪些資源:對所有用戶(hù)的響應完全相同的資源非常適合由CDN以及其他中間緩存進(jìn)行緩存。
為每個(gè)資源確定最佳緩存周期:不同的資源可能有不同的更新要求。為每個(gè)資源審核并確定合適的max-age。
確定最合適您的網(wǎng)站的緩存層次結構:您可以通過(guò)為HTML文檔組合使用包含內容指紋的資源網(wǎng)址和短時(shí)間或no-cache周期,來(lái)控制客戶(hù)端獲取更新的速度。
最大限度減少攪動(dòng):某些資源的更新比其他資源頻繁。如果資源的特定部分(例如JavaScript函數或CSS樣式集)會(huì )經(jīng)常更新,可以考慮將其代碼作為單獨的文件提供。這樣一來(lái),每次獲取更新時(shí),其余內容(例如變化不是很頻繁的內容庫代碼)可以從緩存獲取,從而最大限度減少下載的內容大小
文章的最后我們還要說(shuō)一下內存緩存(from memory cache)和硬盤(pán)緩存(from disk cache)。
內存緩存有兩個(gè)特點(diǎn),分別是快速讀取和時(shí)效性。
快速讀?。簝却鎿Q粗會(huì )將編譯解析后的文件,直接存入該進(jìn)程的內存中,占據該進(jìn)程一定的內存資源,以便下次運行時(shí)的快速讀取
時(shí)效性:一旦該進(jìn)程關(guān)閉,則該進(jìn)程的內存會(huì )被清空
硬盤(pán)緩存- 則是將緩存直接寫(xiě)入硬盤(pán)文件中,讀取緩存需要對該緩存存放的硬盤(pán)文件進(jìn)行I/O操作,然后重新解析該緩存內容,讀取復雜,速度比內存緩存慢。
那么哪些文件會(huì )被放入內存中呢?
事實(shí)上,這個(gè)劃分規則,一直以來(lái)是沒(méi)有定論的。不過(guò)想想也可以理解,內存時(shí)有限的,很多時(shí)候需要先考慮即時(shí)呈現的內存余量,再根據具體的情況決定分配給內存和磁盤(pán)的資源量的比重——資源存放的位置具有一定的隨機性。
雖然劃分規則沒(méi)有定論,但根據日常開(kāi)發(fā)中觀(guān)察的結果,我們至少可以總結出這樣的規律:資源存不存內存,瀏覽器秉承的是“節約原則”。我們發(fā)現,Base64格式的圖片,幾乎永遠可以被塞進(jìn)memory cache,這可以視作瀏覽器為節省渲染開(kāi)銷(xiāo)的“自保行為”;此外,體積不大的 JS、CSS 文件,也有較大地被寫(xiě)入內存的幾率——相比之下,較大的 JS、CSS 文件就沒(méi)有這個(gè)待遇了,內存資源是有限的,它們往往被直接甩進(jìn)磁盤(pán)。
瀏覽器讀取緩存的順序為memory –> disk
好啦,著(zhù)急忙慌整完了,正好零點(diǎn),碎覺(jué)碎覺(jué)。明天還要考試,關(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
聯(lián)系客服