最近我在做前端面試題總結(jié)系列,感興趣的朋友可以添加關(guān)注,歡迎指正、交流。
爭(zhēng)取每個(gè)知識(shí)點(diǎn)能夠多總結(jié)一些,至少要做到在面試時(shí),針對(duì)每個(gè)知識(shí)點(diǎn)都可以侃起來,不至于啞火。
前言
通過前面的介紹,我們知道 HTTP 緩存分為兩種:
- 強(qiáng)緩存
- 協(xié)商緩存
在上一篇文章中,我們了解了 HTTP 強(qiáng)緩存,今天我們來了解一下協(xié)商緩存相關(guān)的內(nèi)容。
協(xié)商緩存
特點(diǎn)
協(xié)商緩存,也稱為對(duì)比緩存,從名稱可以看出,它沒有強(qiáng)制緩存那么霸道,可以有商有量的來確定是否使用緩存資源。
協(xié)商緩存機(jī)制下,瀏覽器需要發(fā)送緩存標(biāo)識(shí),去向服務(wù)器驗(yàn)證緩存標(biāo)識(shí)是否有效,進(jìn)而判斷是重新發(fā)起請(qǐng)求、下載完整的響應(yīng),還是從本地獲取緩存的資源。
如果服務(wù)端提示緩存資源未改動(dòng)(Not Modified),資源會(huì)被重定向到瀏覽器緩存,這種情況下網(wǎng)絡(luò)請(qǐng)求對(duì)應(yīng)的狀態(tài)碼是 304,比如:
規(guī)則
協(xié)商緩存的整體規(guī)則如下所示:
從上圖可以看出,雖然客戶端仍然發(fā)起了 HTTP 請(qǐng)求服務(wù)器,但是服務(wù)器只做了標(biāo)志對(duì)比來確認(rèn)是否使用緩存,如果確認(rèn)使用緩存,就不會(huì)再返回具體的資源了。這樣做雖然沒有減少請(qǐng)求數(shù)量,但是極大減小了請(qǐng)求負(fù)荷,可以明顯提升請(qǐng)求速度和減小網(wǎng)絡(luò)帶寬。
上圖是緩存標(biāo)識(shí)正常有效的時(shí)序圖,但其實(shí)協(xié)商緩存的驗(yàn)證結(jié)果也存在兩種情況:
- 標(biāo)識(shí)有效
- 標(biāo)識(shí)過期
協(xié)商緩存需要配合強(qiáng)緩存使用,使用協(xié)商緩存需要先設(shè)置 Cache-Control:no-cache 或者 pragma:no-cache 來告訴瀏覽器不走強(qiáng)緩存。
標(biāo)識(shí)過期
屬性
對(duì)于協(xié)商緩存來說,緩存標(biāo)識(shí)的傳遞是我們著重需要理解的,它在 Response Header 和 Request Header 之間進(jìn)行傳遞。
緩存標(biāo)識(shí)可以分為兩類:
- Last-Modified 和 If-Modified-Since
- Etag 和 If-None-Match
我們一般會(huì)說,協(xié)商緩存的緩存標(biāo)識(shí)是 Last-Modified(最后修改時(shí)間) 和 Etag(標(biāo)簽或名稱),因?yàn)樗鼈儍蓚€(gè)都是由服務(wù)端確定并返回的。
瀏覽器攜帶的是具有判斷意味的屬性 —— If-Modified-Since(從什么時(shí)間以來是否改變) 和 If-None-Match(是否匹配不到)。
緩存標(biāo)識(shí)的攜帶位置如下圖所示:
在具體的網(wǎng)絡(luò)請(qǐng)求中,緩存標(biāo)識(shí)如下圖所示:
Last-Modified 和 If-Modified-Since
Last-Modified 和 If-Modified-Since 是 HTTP 1.0 引入的。
Last-Modified
當(dāng)瀏覽器第一次訪問一個(gè)資源的時(shí)候,服務(wù)器會(huì)在 Response 、Header 中返回一個(gè) Last-Modified,代表這個(gè)資源最后的修改時(shí)間。
If-Modified-Since
再次請(qǐng)求服務(wù)器時(shí),請(qǐng)求頭會(huì)攜帶此字段,值為上次請(qǐng)求時(shí)服務(wù)器返回的 Last-Modified 的值。
服務(wù)器收到請(qǐng)求后發(fā)現(xiàn)有頭 If-Modified-Since 則與被請(qǐng)求資源的最后修改時(shí)間進(jìn)行比對(duì):
- 若資源的最后修改時(shí)間大于 If-Modified-Since,說明資源又被改動(dòng)過,則響應(yīng)整片資源內(nèi)容,返回狀態(tài)碼 200 和最新的資源,響應(yīng)頭中攜帶最新的緩存標(biāo)識(shí) Last-Modified。
- 若資源的最后修改時(shí)間小于或等于 If-Modified-Since,說明資源無新修改,則響應(yīng) HTTP 304,告知瀏覽器繼續(xù)使用所保存的 cache。
缺陷
使用 Last-Modified 是有一定缺陷的:
- 如果資源更新的速度是秒以下單位,那么該緩存是不能被使用的,因?yàn)?If-Modified-Since 只能檢查到以秒為最小計(jì)量單位的時(shí)間差。
- 如果文件是通過服務(wù)器動(dòng)態(tài)生成的,那么該方法的更新時(shí)間永遠(yuǎn)是生成的時(shí)間,盡管文件可能沒有變化,所以起不到緩存的作用。
- 我們編輯了文件,但文件的內(nèi)容沒有改變。服務(wù)端并不清楚我們是否真正改變了文件,它仍然通過最后編輯時(shí)間進(jìn)行判斷。因此這個(gè)資源在再次被請(qǐng)求時(shí),會(huì)被當(dāng)做新資源,進(jìn)而引發(fā)一次完整的響應(yīng)——不該重新請(qǐng)求的時(shí)候,也會(huì)重新請(qǐng)求。
為了解決上面服務(wù)器沒有正確感知文件變化的問題,Etag 作為 Last-Modified 的補(bǔ)充出現(xiàn)了。
Etag 和 If-None-Match
Etag 和 If-None-Match 是一對(duì)報(bào)文頭,屬于HTTP 1.1。
ETag 和 If-None-Match 的值是一串 hash 碼,代表的是一個(gè)資源的標(biāo)識(shí)符,當(dāng)服務(wù)端的文件變化的時(shí)候,它的 hash 碼會(huì)隨之改變。
Etag
服務(wù)器響應(yīng)請(qǐng)求時(shí),告訴瀏覽器當(dāng)前資源在服務(wù)器的唯一標(biāo)識(shí)(生成規(guī)則由服務(wù)器決定)。
ETag 又有強(qiáng)弱校驗(yàn)之分,如果 hash 碼是以 "W/" 開頭的一串字符串,說明此時(shí)協(xié)商緩存的校驗(yàn)是弱校驗(yàn)的,只有服務(wù)器上的文件差異(根據(jù) ETag 計(jì)算方式來決定)達(dá)到能夠觸發(fā) hash 值后綴變化的時(shí)候,才會(huì)真正地請(qǐng)求資源,否則返回 304 并加載瀏覽器緩存。
If-None-Match
再次請(qǐng)求服務(wù)器時(shí),通過此字段通知服務(wù)器客戶段緩存數(shù)據(jù)的唯一標(biāo)識(shí)。
服務(wù)器收到請(qǐng)求后發(fā)現(xiàn)有頭 If-None-Match 則與被請(qǐng)求資源的唯一標(biāo)識(shí)進(jìn)行比對(duì):
- 不同,說明資源又被改動(dòng)過,則響應(yīng)整片資源內(nèi)容,返回狀態(tài)碼 200。
- 相同,說明資源無新修改,則響應(yīng) HTTP 304,告知瀏覽器繼續(xù)使用所保存的 cache。
缺陷
Etag 的生成過程需要服務(wù)器額外付出開銷,會(huì)影響服務(wù)端的性能,這是它的弊端。
因此啟用 Etag 需要我們審時(shí)度勢(shì):
- Etag 并不能替代 Last-Modified,它只能作為 Last-Modified 的補(bǔ)充和強(qiáng)化存在。
- Etag 在感知文件變化上比 Last-Modified 更加準(zhǔn)確,優(yōu)先級(jí)也更高。
- 當(dāng) Etag 和 Last-Modified 同時(shí)存在時(shí),以 Etag 為準(zhǔn)。
兩種屬性比較
- 在精確度上,Etag 要優(yōu)于 Last-Modified,Last-Modified 的時(shí)間單位是秒,如果某個(gè)文件在 1 秒內(nèi)改變了多次,那么他們的 Last-Modified 其實(shí)并沒有體現(xiàn)出來修改,但是 Etag 每次都會(huì)改變確保了精度。
- 在性能上,Etag 要遜于 Last-Modified,畢竟 Last-Modified 只需要記錄時(shí)間,而 Etag 需要服務(wù)器通過算法來計(jì)算出一個(gè) hash 值。
在優(yōu)先級(jí)上,服務(wù)器校驗(yàn)優(yōu)先考慮 Etag。
總結(jié)
總結(jié)一下上面的內(nèi)容:
- 協(xié)商緩存是依靠緩存標(biāo)識(shí)來判斷資源是否有效。
- 緩存標(biāo)識(shí)包括 Last-Modified(If-Modified-Since)和 Etag(If-None-Match)。
- 響應(yīng)頭攜帶的是 Last-Modified 和 Etag。
- 請(qǐng)求頭攜帶的是 If-Modified-Since 和 If-None-Match。
- Etag 是 Last-Modified 的補(bǔ)充和完善,并不能完全替代 Last-Modified。
- Etag 的優(yōu)先級(jí)高于 Last-Modified。
- Last-Modified 的性能要高于 Etag,但是精確性卻遜色于 Etag。
以上就是 HTTP 協(xié)商緩存的相關(guān)內(nèi)容。
~
~本文完,感謝閱讀!
~
學(xué)習(xí)有趣的知識(shí),結(jié)識(shí)有趣的朋友,塑造有趣的靈魂!
大家好,我是〖編程三昧〗的作者 隱逸王,我的公眾號(hào)是『編程三昧』,歡迎關(guān)注,希望大家多多指教!
你來,懷揣期望,我有墨香相迎! 你歸,無論得失,唯以余韻相贈(zèng)!
知識(shí)與技能并重,內(nèi)力和外功兼修,理論和實(shí)踐兩手都要抓、兩手都要硬!