|
作者:程序猿小卡(@程序猿小卡_casper)
鏈接:www.cnblogs.com/chyingp/p/no-cache-vs-must-revalidate.html
引言稍微了解HTTP協(xié)議的前端同學(xué),相比對Cache-Control不會感到陌生,性能優(yōu)化時經(jīng)常都會跟它打交道。 常見的值有有private、public、no-store、no-cache、must-revalidate、max-age等。 各個取值所代表的含義,網(wǎng)上總結(jié)挺多的,這里就不打算再進(jìn)行逐一介紹,感興趣的可以一起探討交流。 本文僅挑no-cache、must-revalidate 這兩個進(jìn)行值進(jìn)行探究對比。在項目實(shí)踐中,這兩個值用的比較多,也比較容易搞混。 Cache-Control: no-cache Cache-Control: max-age=60, must-revalidate
傳送門:RFC2616關(guān)于Cache-Control首部的介紹。 如果對論證過程不感興趣,也可以直接跳到“對比結(jié)論”小節(jié)查看結(jié)論。 no-cache、must-revalidate簡介上面的介紹涉及三個主體:瀏覽器、緩存服務(wù)器、源服務(wù)器。下面小節(jié)會簡單進(jìn)行介紹。 瀏覽器、緩存服務(wù)器、源服務(wù)器緩存服務(wù)器作用如下。緩存服務(wù)器不是必須的,瀏覽器可也可與源服務(wù)器直接通信。 加速資源訪問速度,降低源服務(wù)器的負(fù)載。緩存服務(wù)器從源服務(wù)器獲取資源,并返回給瀏覽器。此外,緩存服務(wù)器一般還會在本地保存資源的副本,當(dāng)有相同的資源請求到來,緩存服務(wù)器可返回資源副本,以此提高資源訪問速度。

對比測試場景、環(huán)境準(zhǔn)備對比測試場景下文會通過以下兩種場景的對比測試,來探究no-cache、must-revalidate的區(qū)別。 瀏覽器 直接訪問 源服務(wù)器。 瀏覽器 通過 緩存服務(wù)器,間接訪問 源服務(wù)器。
環(huán)境準(zhǔn)備1、下載實(shí)驗代碼:可以訪問github主頁獲取,也可通過git clone下載到本地。 git clone https://github.com/chyingp/tech-experiment.git cd tech-experiment/2016.10.25-cache-control/ npm install
2、安裝Squid,步驟略,下載地址。 3、可選:啟動Squid,并將本地http代理設(shè)置為Squid的ip和端口。 備注:測試場景“通過緩存服務(wù)器,間接訪問源服務(wù)器資源”時,才需要這一步。

4、可選:將本地代理設(shè)置為Charles的地址,然后將Charles的代理地址設(shè)置為squid的代理地址。(避免瀏覽器開發(fā)者工具對request header的修改,干擾實(shí)驗結(jié)果) 場景一:瀏覽器->源服務(wù)器首先,通過以下腳本啟動本地服務(wù)器(源服務(wù)器)。 cd connect-directly node server.js
Cache-Control: no-cache用例1:二次訪問,源服務(wù)器 上 資源 未發(fā)生變化 訪問地址為:http://127.0.0.1:3000/no-cache 步驟一:第一次訪問,返回內(nèi)容如下??梢钥吹?,返回了Cache-Control: no-cache。 
HTTP/1.1 200 OK X-Powered-By: Express Cache-Control: no-cache Content-Type: text/html; Content-Length: 11 ETag: W/'b-s0vwqaICscfrawwztfPIiA' Date: Wed, 26 Oct 2016 07:46:28 GMT Connection: keep-alive
步驟二:第二次訪問,返回內(nèi)容如下。返回狀態(tài)碼為304 Not Modified,表示經(jīng)過校驗,源服務(wù)器上的資源沒有變化,瀏覽器可以采用本地副本。

HTTP/1.1 304 Not Modified X-Powered-By: Express Cache-Control: no-cache ETag: W/'b-s0vwqaICscfrawwztfPIiA' Date: Wed, 26 Oct 2016 07:47:31 GMT Connection: keep-alive
用例2:二次訪問,源服務(wù)器 上 資源 發(fā)生變化 步驟一:訪問地址為:http://127.0.0.1:3000/no-cache?change=1 備注:change=1告訴源服務(wù)器,每次訪問都返回不同內(nèi)容 步驟一:第一次訪問,內(nèi)容如下,不贅述。 
HTTP/1.1 200 OK X-Powered-By: Express Cache-Control: no-cache Content-Type: text/html; charset=utf-8 Content-Length: 11 ETag: W/'b-8n8r0vUN mIIQCegzmqpuQ' Date: Wed, 26 Oct 2016 07:48:01 GMT Connection: keep-alive
步驟二:第二次訪問,返回內(nèi)容如下。注意Etag變化了,表示源服務(wù)器資源已發(fā)生變化。于是狀態(tài)碼為200 OK,源服務(wù)器返回新版本的資源給瀏覽器。

HTTP/1.1 200 OK X-Powered-By: Express Cache-Control: no-cache Content-Type: text/html; charset=utf-8 Content-Length: 11 ETag: W/'b-0DK7Mx61dfZc1vIPJDSNSQ' Date: Wed, 26 Oct 2016 07:48:38 GMT Connection: keep-alive
Cache-Control: must-revalidate訪問地址:http://127.0.0.1:3000/must-revalidate 可選參數(shù)說明: 用例1:二次訪問,瀏覽器緩存未過期 訪問地址:http://127.0.0.1:3000/must-revalidate?max-age=10 備注:max-age=10表示,希望資源緩存10s 步驟一:第一次訪問,返回內(nèi)容如下。 
HTTP/1.1 200 OK X-Powered-By: Express Cache-Control: max-age=10, must-revalidate Content-Type: text/html; charset=utf-8 Content-Length: 16 ETag: W/'10-dK948plT5cojN3y7Cy717w' Date: Wed, 26 Oct 2016 08:06:16 GMT Connection: keep-alive
步驟二:第二次訪問(在10s內(nèi)),如下截圖所示,瀏覽器直接從本地緩存里讀取資源副本,并沒有重新發(fā)起HTTP請求。

用例2:二次訪問,瀏覽器緩存已過期,源服務(wù)器 資源未變化 步驟一:第一次訪問略過。第二次訪問如下截圖所示(10s后),返回304 Not Modified。 
HTTP/1.1 304 Not Modified X-Powered-By: Express Cache-Control: max-age=10, must-revalidate ETag: W/'10-dK948plT5cojN3y7Cy717w' Date: Wed, 26 Oct 2016 08:09:22 GMT Connection: keep-alive
用例3:瀏覽器緩存已過期,源服務(wù)器 資源 已變化 訪問地址:http://127.0.0.1:3000/must-revalidate?max-age=10&change=1 步驟一:第一次訪問,截圖如下。 
步驟二:第二次訪問(10s后),返回截圖如下,可以看到返回了200。 
場景2:瀏覽器->緩存服務(wù)器->源服務(wù)器從上面的對比實(shí)驗已經(jīng)知道,在不經(jīng)過緩存服務(wù)器的情況下,no-cache、must-revalidate在緩存校驗方面的差別。 接下來,我們再看下,引入緩存服務(wù)器后,二者表現(xiàn)的差異點(diǎn)。 備注:下文我們會通過查看Squid的訪問日志,來確認(rèn)緩存服務(wù)器的行為。這里對日志中的幾個關(guān)鍵字先粗略解釋下: 再次貼上之前的圖。 
Cache-Control: no-cache用例1:chrome第一次訪問資源 chrome訪問截圖如下:200 ok 
squid日志:TCP_MISS,表示沒有命中本地資源副本。 1477501799.573 17 127.0.0.1 TCP_MISS/200 299 GET http://127.0.0.1:3000/no-cache - HIER_DIRECT/127.0.0.1 text/html
用例2:chrome再次訪問該資源。且源服務(wù)器上,該資源未變化 訪問地址:http://127.0.0.1:3000/no-cache 第一次訪問略。第二次訪問,chrome訪問截圖如下: 
squid訪問日志如下:TCP_MISS/304 。表示緩存服務(wù)器 聯(lián)系了 源服務(wù)器,發(fā)現(xiàn)內(nèi)容沒變化,于是返回304。 1477501987.785 1 127.0.0.1 TCP_MISS/304 238 GET http://127.0.0.1:3000/no-cache - HIER_DIRECT/127.0.0.1 -
用例3:chrome再次訪問該資源。且源服務(wù)器上,該資源已變化 訪問地址:http://127.0.0.1:3000/no-cache?change=1 備注:change=1 表示強(qiáng)制每次訪問源服務(wù)器,返回的資源都是新的。 第一次訪問略。第二次訪問,chrome截圖如下,狀態(tài)碼為200。 
從squid日志來看,緩存服務(wù)器 訪問 源服務(wù)器,并返回200給瀏覽器。 1477647837.216 1 127.0.0.1 TCP_MISS/200 299 GET http://127.0.0.1:3000/no-cache? - HIER_DIRECT/127.0.0.1 text/html
Cache-Control: must-revalidate用例1:緩存服務(wù)器 已存在 資源副本,且該資源副本 未過期 訪問地址:http://127.0.0.1:3000/must-revalidate?max-age=900 備注:max-age=900表示資源有效期是900s 步驟一: chrome第一次訪問 該資源,緩存服務(wù)器上沒有該資源副本,于是訪問源服務(wù)器。最終,緩存服務(wù)器給瀏覽器返回200。此時,緩存服務(wù)器squid上有了資源的副本。 步驟二: firefox第一次訪問 該資源(900s內(nèi))。緩存服務(wù)器上已有該資源副本,且該副本未過期。于是,緩存服務(wù)器給firefox返回該資源副本,且狀態(tài)碼為200。(緩存命中) 為了驗證步驟二中,緩存服務(wù)器 返回的是本地資源的副本,查看squid日志。其中,第二條就是firefox的訪問記錄,TCP_MEM_HIT/200表示命中本地緩存。 1477648947.594 5 127.0.0.1 TCP_MISS/200 325 GET http://127.0.0.1:3000/must-revalidate? - HIER_DIRECT/127.0.0.1 text/html 1477649012.625 0 127.0.0.1 TCP_MEM_HIT/200 333 GET http://127.0.0.1:3000/must-revalidate? - HIER_NONE/- text/html
用例2:緩存服務(wù)器 已存在 資源副本,該資源副本已過期,但源服務(wù)器上 資源未改變 訪問鏈接:http://127.0.0.1:3000/must-revalidate?max-age=10 用chrome先后訪問該資源,其間間隔超過10s。第二次訪問時,chrome收到響應(yīng)如下。 
查看squid日志??梢钥吹?,狀態(tài)為TCP_MISS/304,表示本地副本已過期,跟源服務(wù)器進(jìn)行校驗,發(fā)現(xiàn)源服務(wù)器上資源未改變。于是,給瀏覽器返回304。 1477649429.105 11 127.0.0.1 TCP_MISS/304 258 GET http://127.0.0.1:3000/must-revalidate? - HIER_DIRECT/127.0.0.1 -
用例3:緩存服務(wù)器 已存在 資源副本,該資源副本 已過期,但源服務(wù)器上 資源已改變 訪問地址:http://127.0.0.1:3000/must-revalidate?max-age=10&change=1 用chrome先后訪問該資源,其間間隔超過10s。第二次訪問時,chrome收到響應(yīng)如下 
squid日志如下,狀態(tài)都是TCP_MISS/200,表示沒有命中緩存。 1477650702.807 8 127.0.0.1 TCP_MISS/200 325 GET http://127.0.0.1:3000/must-revalidate? - HIER_DIRECT/127.0.0.1 text/html 1477651020.516 4 127.0.0.1 TCP_MISS/200 325 GET http://127.0.0.1:3000/must-revalidate? - HIER_DIRECT/127.0.0.1 text/html
對比結(jié)論以下針對的都是瀏覽器第n次訪問資源。(n>1) 不考慮緩存服務(wù)器| 首部 | 本地緩存是否過期 | 源服務(wù)器資源是否改變 | 是否重新校驗 | 狀態(tài)碼 |
|---|
| no-cache | 不確定 | 否 | 是 | 304 | | no-cache | 不確定 | 是 | 是 | 200 | | must-revalidate | 否 | 是/否 | 否 | 200(來自瀏覽器緩存) | | must-revalidate | 是 | 否 | 是 | 304 | | must-revalidate | 是 | 是 | 是 | 200 |
考慮緩存服務(wù)器| 首部 | 本地緩存是否過期 | 緩存服務(wù)器副本是否過期 | 源服務(wù)器資源是否改變 | 是否重新校驗 | 狀態(tài)碼 |
|---|
| no-cache | 不確定 | 不確定 | 否 | 是 | 304 | | no-cache | 不確定 | 不確定 | 是 | 是 | 200 | | must-revalidate | 否 | 是/否 | 是/否 | 否 | 200(來自瀏覽器緩存) | | must-revalidate | 是 | 否 | 是/否 | 是 | 304(來自緩存服務(wù)器) | | must-revalidate | 是 | 是 | 否 | 是 | 304 | | must-revalidate | 是 | 是 | 是 | 是 | 200 |
寫在后面經(jīng)過一輪對比測試,發(fā)現(xiàn)no-cache、must-revalidate這兩個值還是蠻有意思的。實(shí)際上,由于篇幅原因,這里還有一些內(nèi)容尚未進(jìn)行對比實(shí)驗。比如: 當(dāng)must-revalidate或no-cache跟max-stale一起使用時的表現(xiàn)。 no-cache跟max-age=0, mustvalidate的區(qū)別。
no-chche制定具體的字段名時,跟不指明具體字段名時,緩存校驗行為上的區(qū)別。
proxy-revalidate跟must-revalidate的區(qū)別。
緩存服務(wù)器本身優(yōu)化算法對實(shí)驗結(jié)果的影響。
對比實(shí)驗過程比較枯燥繁瑣,如有不嚴(yán)謹(jǐn)或錯漏的地方,敬請指出 :) 這里留個經(jīng)常會碰到的問題,供讀者探討:no-cache跟max-age=0, mustvalidate的區(qū)別。 相關(guān)鏈接RFC2616 14.9: Cache-Control https://www./Protocols/rfc2616/rfc2616-sec14.html#sec14.9
關(guān)注「前端大全」 看更多精選前端技術(shù)文章 ↓↓↓
|