摘要:緩存主要通過首部來控制。表示當(dāng)前響應(yīng)數(shù)據(jù)是單個用戶所獨(dú)占的,只能被客戶端緩存,不能被代理服務(wù)器緩存。其值是任意整數(shù),和負(fù)數(shù)表示緩存過期,正數(shù)值加上當(dāng)前響應(yīng)頭中的首部值即為過期時間??蛻舳耸盏胶螅苯邮褂镁彺娴?,同時更新緩存有效期。
無論是軟件應(yīng)用還是硬件應(yīng)用,緩存都扮演著重要的角色,其對提升性能的重要性無可置疑。
本文主要介紹 HTTP 緩存,涉及其原理和應(yīng)用。HTTP 緩存主要通過 HTTP 首部來控制。
緩存示例先看一個簡單的緩存示例:
瀏覽器首次請求 app.js 時,服務(wù)器會返回資源內(nèi)容和相關(guān)頭部,其中 Cache-Control: max-age=120 告訴瀏覽器說,這個資源的緩存有效期為 120 秒,從當(dāng)前時間 Date: Mon, 05 Mar 2018 08:00:00 GMT 開始算起。瀏覽器收到資源后便將 app.js 及其相應(yīng)頭部存儲在本地。
如果在 05 Mar, 2018 08:02:00 GMT 之前再次請求 app.js ,則瀏覽器會直接使用存儲在本地的資源,而不用再次向服務(wù)器發(fā)起請求。
這個過程中,我們就說 app.js 被緩存且命中了。
基本概念在進(jìn)一步理解緩存之前,先看下跟緩存相關(guān)的幾個概念:
命中:請求數(shù)據(jù)不需再次下載,可以直接使用緩存數(shù)據(jù)
過期:緩存數(shù)據(jù)超過設(shè)置的有效時間,將被標(biāo)記為“陳舊”
驗(yàn)證:判斷過期緩存是否仍然有效,需要與服務(wù)器交互
失效:緩存數(shù)據(jù)不再有效,需要從服務(wù)端重新下載新數(shù)據(jù)
基本理解HTTP 緩存涉及到請求-響應(yīng)鏈上的多個角色,包括客戶端(本文指瀏覽器)、代理和服務(wù)器。
其中,瀏覽器自身也實(shí)現(xiàn)了緩存功能。瀏覽器在請求資源時,總是先從本地緩存中查找,如果找到未過期資源,則直接使用,否則向服務(wù)器發(fā)起請求。
代理也是服務(wù)器的一種,但一般情況下不會把它多帶帶抽出來分析,只有在跟它有關(guān)的地方會把它區(qū)分于源服務(wù)器。所以,下文的示例圖中將不會把它列進(jìn)去。
HTTP 緩存的理解基本上可以總結(jié)為三個問題:
緩存數(shù)據(jù)可以存儲在哪些設(shè)備上?(WHERE)
緩存數(shù)據(jù)如何判斷過期?(HOW)
過期緩存內(nèi)容是否真的需要重新下載?(WHETHER)
問題 1 說明存儲緩存數(shù)據(jù)的設(shè)備是多樣的,可以存儲于各級代理服務(wù)器,也可以存儲于瀏覽器本地。
問題 2 說明使用什么辦法來判斷緩存數(shù)據(jù)是否已經(jīng)過期,當(dāng)然是比較時間啦,那么如何比較呢?
問題 3 說明緩存雖然過期了,但是其內(nèi)容仍然可能與服務(wù)端一致,這時就沒必要重新下載相同數(shù)據(jù),只需要向服務(wù)端詢問下是否可以繼續(xù)使用緩存即可。
帶著上面三個問題去理解 HTTP 緩存頭部設(shè)置會更有助于理解和記憶。
有人根據(jù)是否需要進(jìn)行問題 3 中的重新驗(yàn)證把緩存策略的設(shè)置分為強(qiáng)緩存和協(xié)商緩存,強(qiáng)緩存無須再次驗(yàn)證的緩存策略,協(xié)商緩存是需要再次驗(yàn)證的緩存策略。
兩者的區(qū)別在于,協(xié)商緩存多發(fā)起了一次 HTTP 請求。
HTTP 緩存主要通過 HTTP 首部來實(shí)現(xiàn)緩存控制。這些與緩存相關(guān)的 HTTP 首部這里統(tǒng)稱為緩存首部,具體首部如下表所示。
首部字段 | 首次定義 | 首部類型 |
---|---|---|
Pragma | HTTP/1.0 | 通用首部 |
Age | HTTP/1.1 | 響應(yīng)首部 |
Expires | HTTP/1.0 | 實(shí)體首部 |
Cache-Control | HTTP/1.1 | 通用首部 |
Etag | HTTP/1.1 | 響應(yīng)首部 |
If-Match | HTTP/1.1 | 請求首部 |
If-None-Match | HTTP/1.1 | 請求首部 |
If-Modified-Since | HTTP/1.0 | 請求首部 |
Last-Modified | HTTP/1.0 | 實(shí)體首部 |
其中,“首次定義”是指首次出現(xiàn)在哪個 HTTP 版本。之所以列出這項(xiàng)內(nèi)容,是因?yàn)閷?shí)際應(yīng)用需要考慮兼容舊版 HTTP 。
現(xiàn)代的 HTTP 緩存策略主要使用 Cache-Control 實(shí)現(xiàn),它是目前最新的緩存首部,用于取代較老的緩存首部如 Pragma 、Expires 等。所以應(yīng)用中應(yīng)該傾向于使用 Cache-Control 。但是為了支持只實(shí)現(xiàn)了 HTTP/1.0 的客戶端設(shè)備,服務(wù)端通常還是都會同時設(shè)置 Expires、Pragma 和 Cache-Control 等,此時 Cache-Control 會有更高的優(yōu)先級。提醒一下,現(xiàn)代瀏覽器都已支持 Cache-Control 。
Cache-ControlCache-Control 是通用首部,這意味著它既可以出現(xiàn)在請求中,也可以出現(xiàn)在響應(yīng)中。
Cache-Control 的值可由多個字段組合而成,以逗號分隔,如 Cache-Control: private,max-age=3600 。下面對常用的可取字段進(jìn)行說明。
public: 表示當(dāng)前響應(yīng)數(shù)據(jù)所有用戶共享的,可以被任何設(shè)備緩存,包括客戶端、代理服務(wù)器等。
private: 表示當(dāng)前響應(yīng)數(shù)據(jù)是單個用戶所獨(dú)占的,只能被客戶端緩存,不能被代理服務(wù)器緩存。
max-age=
max-stale[=
min-fresh=
s-maxage=
no-cache: 并非字面意思,它并非禁止緩存,而是強(qiáng)制在使用已緩存數(shù)據(jù)之前,需要去服務(wù)端驗(yàn)證一下是否可以使用緩存數(shù)據(jù)。
no-store: 真正的禁止緩存,任何設(shè)備都不允許緩存,每次請求都需要向服務(wù)端重新獲取數(shù)據(jù)。
no-transform: 表示響應(yīng)的實(shí)體數(shù)據(jù)不應(yīng)被轉(zhuǎn)換。Content-Encoding 、Content-Range 和 Content-Type 首部也不能被修改。實(shí)際應(yīng)用中,有些代理服務(wù)器會對圖片資源進(jìn)行格式轉(zhuǎn)換以節(jié)省空間或者帶寬。
作為通用首部,其部分指令值可以出現(xiàn)在請求首部,也可以出現(xiàn)在響應(yīng)首部,兩者可能略有區(qū)別:
指令值 | 請求 | 響應(yīng) |
---|---|---|
public | - | 可共享數(shù)據(jù),可被任何設(shè)備緩存 |
private | - | 用戶私有數(shù)據(jù),只能被客戶端緩存 |
no-cache | 使用前需驗(yàn)證 | 使用前需驗(yàn)證 |
no-store | 禁止使用緩存數(shù)據(jù) | 禁止緩存 |
max-age | 要求資源的 age 小于這個時間 | 最大過期時間 |
min-fresh | 要求資源至少還剩余多少過期時間 | - |
max-stale | 超過過期時間多少秒內(nèi)仍愿意接受 | - |
no-transform | 不要轉(zhuǎn)換格式 | 不要轉(zhuǎn)換格式 |
這些指令用在請求首部的情況比較少見,最可能接觸的地方是 Chrome DevTools 中的 Network 標(biāo)簽頁。
其中,有個 Disable cache 選項(xiàng),選中后 DevTools 會自動給所有請求頭部加上 Cache-Control: no-cache 首部,以告訴瀏覽器和代理使用本地緩存之前必須先驗(yàn)證。
If-Modified-Since 首部比較的是資源的修改時間,精度為秒,是一種緩存過期后的常用驗(yàn)證方式。一般來說,驗(yàn)證資源是否修改過,對比資源的修改時間是一種最簡單的辦法。
使用過程如下:
客戶端首次請求 app.js 時,服務(wù)器響應(yīng)帶上 Last-Modified 首部,告訴客戶端當(dāng)前資源的最后修改時間??蛻舳烁鶕?jù) Cache-Control: max-age=120 ,把 app.js 和響應(yīng)首部緩存起來。
客戶端再次發(fā)起請求 app.js 時,把之前保存的 Last-Modified 時間放入 If-Modified-Since 首部發(fā)給服務(wù)器。服務(wù)器發(fā)現(xiàn)資源的 Last-Modified 時間沒有發(fā)生改變,于是直接響應(yīng) 304 ??蛻舳耸盏?304 后,直接使用緩存的 app.js ,同時更新緩存有效期。
客戶端再次發(fā)起請求 app.js 時,把之前保存的 Last-Modified 時間放入 If-Modified-Since 首部發(fā)給服務(wù)器。服務(wù)器發(fā)現(xiàn)資源的 Last-Modified 時間已經(jīng)發(fā)生改變,于是響應(yīng) 200 ,將修改后的 app.js 和新的 Last-Modified 發(fā)送給客戶端。客戶端收到 200 后,重新下載新的 app.js ,并把新的 app.js 和響應(yīng)首部緩存起來,替換原先的舊緩存。
ETag/If-Matched/If-None-MatchETag 叫實(shí)體標(biāo)簽(Entity Tag),用于表示實(shí)體資源是否發(fā)生變化,其生成原理類似 MD5 ,也是一種用于驗(yàn)證的首部。當(dāng)響應(yīng)的首部信息或者消息實(shí)體發(fā)生變化時,實(shí)體標(biāo)簽也會改變。
使用過程如下:
客戶端首次請求 app.js 時,服務(wù)器響應(yīng)帶上 ETag 首部,告訴客戶端當(dāng)前資源的實(shí)體標(biāo)簽??蛻舳烁鶕?jù) Cache-Control: max-age=120 ,把 app.js 和響應(yīng)首部緩存起來。
客戶端再次發(fā)起請求 app.js 時,把之前保存的 ETag 值放入 If-None-Match 首部發(fā)給服務(wù)器。服務(wù)器發(fā)現(xiàn)自己的資源 ETag 值并沒有發(fā)生改變,于是直接響應(yīng) 304 。客戶端收到 304 后,直接使用緩存的 app.js ,同時更新緩存有效期。
客戶端再次發(fā)起請求 app.js 時,把之前保存的 ETag 值放入 If-None-Match 首部發(fā)給服務(wù)器。服務(wù)器發(fā)現(xiàn)自己的資源 ETag 值已經(jīng)發(fā)生改變,于是響應(yīng) 200 ,將修改后的 app.js 和新的 ETag 發(fā)送給客戶端??蛻舳耸盏?200 后,重新下載新的 app.js ,并把新的 app.js 和響應(yīng)首部緩存起來,替換原先的舊緩存。
當(dāng)客戶端本地存儲有多個版本的資源時,會把所有的實(shí)體標(biāo)簽都上傳,形如 ETag: "abc","def" ,服務(wù)端會使用 ETag 首部返回匹配中的實(shí)體標(biāo)簽值。
實(shí)體標(biāo)簽分為強(qiáng)標(biāo)簽(Strong ETag)和弱標(biāo)簽(Weak ETag),弱標(biāo)簽以 W/ 開頭,如 ETag: W/"1234" 。強(qiáng)標(biāo)簽使用強(qiáng)比較,弱標(biāo)簽使用弱比較。強(qiáng)比較意味著兩個比較對象的每一個字節(jié)都相同,弱比較意味著兩者語義相同(Semantic Equivalence)。舉個栗子,假如響應(yīng)首部包含一個渲染時間 Rendered-Time,A 響應(yīng)的渲染時間為 365,B 響應(yīng)的渲染時間為 345,兩個響應(yīng)的實(shí)體內(nèi)容一致。這種情況下,我們可以說 A 和 B 弱比較相等,強(qiáng)比較不相等。
一般來說,靜態(tài)內(nèi)容使用強(qiáng)標(biāo)簽,動態(tài)生成的內(nèi)容使用弱標(biāo)簽。
由此可以看出,實(shí)體首部可以解決一些 Last-Modified 無法解決的問題:
某些服務(wù)器不能得到文件的精確的最后修改時間
修改時間變了并不意味著內(nèi)容的改變,比如改完保存后又改回去
修改時間只能精確到秒,一秒內(nèi)的修改無法判斷
If-Match 和 ETag 的另一種用法:避免“空中碰撞”,以防編輯沖突。當(dāng)客戶端使用 PUT 或者 POST 更新服務(wù)端資源時,需要使用 If-Match 來攜帶實(shí)體標(biāo)簽給服務(wù)端,以確??蛻舳艘薷牡馁Y源沒有被別人修改過,避免覆蓋別人的修改。不過這種用法比較少,可以不用深究。
ExpiresExpires 指明資源的過期時間,如 Expires: Wed, 04 Jul 2012 08:26:05 GMT 。非法的日期格式(如 0)將會被當(dāng)做過去的時間,表示該資源已經(jīng)過期。
如果 Expires 和 Cache-Control 的 max-age 或者 s-maxage 同時出現(xiàn),Expires 將被忽略。
AgeAge 表示資源在代理服務(wù)器上已經(jīng)緩存了多久時間,單位為秒。如果是 Age: 0 ,表明該資源剛剛從服務(wù)器獲取。它的計(jì)算方式一般使用代理服務(wù)器當(dāng)前的時間減去緩存資源的 Date 時間。
PragmaPragma 是 HTTP/1.0 中引入的首部,現(xiàn)在使用時一般用于向后兼容 HTTP/1.0,不鼓勵使用。
Pragma: no-cache 的作用與 Cache-Control: no-cache 一致,表示需要跟服務(wù)器進(jìn)行驗(yàn)證后才能使用緩存資源。
啟發(fā)式緩存策略并不是每個服務(wù)器都會返回明確的緩存策略,這種情況下客戶端會采取啟發(fā)式緩存策略。注意,只有在服務(wù)端沒有返回明確的緩存策略時才會激活啟發(fā)式緩存策略。
啟發(fā)式緩存策略會根據(jù)其他的首部信息來計(jì)算一個過期時間,其他的首部通常是 Date 和 Last-Modified 。此時,緩存有效期一般取兩者差值的 10% 。
使用啟發(fā)式緩存策略時,如果超過當(dāng)前時間 24 小時且從未警告過,瀏覽器或者代理服務(wù)器應(yīng)該在響應(yīng)中產(chǎn)生一個警告首部字段 Warning: 113 。
參考資料HTTP/1.0, RFC1945
HTTP/1.1, RFC2616
HTTP/1.1 Caching, RFC7323
HTTP 緩存, Google Developers
The-difference-between-strong-and-weak-ETags
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/61963.html
摘要:的主要組件包含了一個全新的引擎,稱為量子,也稱為。這個新引擎集成了四種不同瀏覽器的最新創(chuàng)新技術(shù),創(chuàng)造出一個全新的超級引擎。這可以發(fā)生在多個圖層上。最終,擁有最高特異性的規(guī)則會勝出。 原文:Inside a Super Fast CSS Engine: Quantum CSS(Aka Stylo), Lin Clark 注:原文發(fā)布于 2017 年 8 月,本文翻譯于 2018 年 4 ...
摘要:性能簡史在年,被創(chuàng)造出來時并不是沖著性能去的。而且在之后的十年發(fā)展中,它的性能一直是很低的。的引入成就了性能提升的一個轉(zhuǎn)折點(diǎn),其執(zhí)行速度比以往快了之多。性能提升也使得在全新的問題上使用成為可能?,F(xiàn)在,極可能是下一個性能轉(zhuǎn)折點(diǎn)。 你可能已經(jīng)聽說 WebAssembly 代碼跑起來非常快。但是你知道這是為什么嗎?在本系列文章中,我們將探究其原因。 何為 WebAssembly WebAss...
摘要:我們還經(jīng)驗(yàn)性地演示了貝葉斯在語言建?;鶞?zhǔn)和生成圖說任務(wù)上優(yōu)于傳統(tǒng),以及通過使用不同的訓(xùn)練方案,這些方法如何改進(jìn)我們的模型。第節(jié)和第節(jié)分別回顧了通過反向傳播做貝葉斯,和通過時間做反向傳播。 摘要在這項(xiàng)工作里,我們探討了一種用于 RNN 的簡單變分貝葉斯方案(straightforward variational Bayes scheme)。首先,我們表明了一個通過時間截斷反向傳播的簡單變化,能...
摘要:為了更好的理解,我們有必要去先理解什么是匯編,以及編譯器是如何產(chǎn)生匯編的。什么是匯編現(xiàn)在,我們來看看外星人的大腦是如何工作的。這些注釋就是匯編,也稱為符號機(jī)器碼。結(jié)束以上的內(nèi)容就是什么是匯編以及它是如何從高級編程語言翻譯過來的。 本文是圖說 WebAssembly 系列文章的第三篇。如果您還未閱讀之前的文章,建議您從第一篇入手。 為了更好的理解 WebAssembly ,我們有必要去先...
閱讀 2412·2021-11-24 10:18
閱讀 3581·2021-09-22 15:35
閱讀 3432·2021-09-13 10:37
閱讀 3858·2021-09-06 15:14
閱讀 2129·2021-09-06 15:02
閱讀 2316·2021-09-02 15:11
閱讀 607·2019-08-30 15:53
閱讀 3136·2019-08-29 16:15