瀏覽器的強緩存和協(xié)商緩存

瀏覽器的強緩存和協(xié)商緩存

原文鏈接:https://github.com/yiliang114/Blog/issues/6

這里說的緩存是指瀏覽器(客戶端)在本地磁盤中對訪問過的資源保存的副本文件疹尾。

瀏覽器緩存主要有以下幾個優(yōu)點:

  1. 減少重復(fù)數(shù)據(jù)請求液南,避免通過網(wǎng)絡(luò)再次加載資源肉瓦,節(jié)省流量。
  2. 降低服務(wù)器的壓力,提升網(wǎng)站性能岗照。
  3. 加快客戶端加載網(wǎng)頁的速度摆尝, 提升用戶體驗。

瀏覽器緩存分為強緩存和協(xié)商緩存逻恐,兩者有兩個比較明顯的區(qū)別:

  1. 如果瀏覽器命中強緩存像吻,則不需要給服務(wù)器發(fā)請求峻黍;而協(xié)商緩存最終由服務(wù)器來決定是否使用緩存,即客戶端與服務(wù)器之間存在一次通信拨匆。
  2. chrome 中強緩存(雖然沒有發(fā)出真實的 http 請求)的請求狀態(tài)碼返回是 200 (from cache)姆涩;而協(xié)商緩存如果命中走緩存的話,請求的狀態(tài)碼是 304 (not modified)惭每。 不同瀏覽器的策略不同骨饿,在 Fire Fox中,from cache 狀態(tài)碼是 304.

其中 from cache 會分為 from disk cache 和 from memory cache. 從內(nèi)存中獲取最快台腥,但是是 session 級別的緩存宏赘,關(guān)閉瀏覽器之后就沒有了。
[圖片上傳失敗...(image-ce437-1580376444419)]

請求流程

瀏覽器在第一次請求后緩存資源黎侈,再次請求時察署,會進(jìn)行下面兩個步驟:

  1. 瀏覽器會獲取該緩存資源的 header 中的信息,根據(jù) response header 中的 expirescache-control 來判斷是否命中強緩存峻汉,如果命中則直接從緩存中獲取資源贴汪。
  2. 如果沒有命中強緩存,瀏覽器就會發(fā)送請求到服務(wù)器俱济,這次請求會帶上 IF-Modified-Since 或者 IF-None-Match, 它們的值分別是第一次請求返回 Last-Modified或者 Etag嘶是,由服務(wù)器來對比這一對字段來判斷是否命中。如果命中蛛碌,則服務(wù)器返回 304 狀態(tài)碼聂喇,并且不會返回資源內(nèi)容,瀏覽器會直接從緩存獲任敌希太;否則服務(wù)器最終會返回資源的實際內(nèi)容,并更新 header 中的相關(guān)緩存字段酝蜒。

借用網(wǎng)上的一張圖片

[圖片上傳失敗...(image-8a99bd-1580376444420)]

強緩存

強緩存是根據(jù)返回頭中的 Expires 或者 Cache-Control 兩個字段來控制的誊辉,都是表示資源的緩存有效時間。

  • Expireshttp 1.0 的規(guī)范亡脑,值是一個GMT 格式的時間點字符串堕澄,比如 Expires:Mon,18 Oct 2066 23:59:59 GMT 。這個時間點代表資源失效的時間霉咨,如果當(dāng)前的時間戳在這個時間之前蛙紫,則判定命中緩存。有一個缺點是途戒,失效時間是一個絕對時間坑傅,如果服務(wù)器時間與客戶端時間偏差較大時,就會導(dǎo)致緩存混亂喷斋。而服務(wù)器的時間跟用戶的實際時間是不一樣是很正常的唁毒,所以 Expires 在實際使用中會帶來一些麻煩蒜茴。
  • Cache-Control這個字段是 http 1.1 的規(guī)范,一般常用該字段的 max-age 值來進(jìn)行判斷浆西,它是一個相對時間粉私,比如 .Cache-Control:max-age=3600 代表資源的有效期是 3600 秒。并且返回頭中的 Date 表示消息發(fā)送的時間室谚,表示當(dāng)前資源在 Date ~ Date +3600s 這段時間里都是有效的毡鉴。不過我在實際使用中常常遇到設(shè)置了 max-age 之后,在 max-age 時間內(nèi)重新訪問資源卻會返回 304 not modified 秒赤,這是由于服務(wù)器的時間與本地的時間不同造成的。當(dāng)然 Cache-Control 還有其他幾個值可以設(shè)置憎瘸, 不過相對來說都很少用了:
    • no-cache 不使用本地緩存入篮。需要使用協(xié)商緩存。
    • no-store直接禁止瀏覽器緩存數(shù)據(jù)幌甘,每次請求資源都會向服務(wù)器要完整的資源潮售, 類似于 network 中的 disabled cache
    • public 可以被所有用戶緩存锅风,包括終端用戶和 cdn 等中間件代理服務(wù)器酥诽。
    • private 只能被終端用戶的瀏覽器緩存。

如果 Cache-ControlExpires 同時存在的話皱埠, Cache-Control 的優(yōu)先級高于 Expires 肮帐。

協(xié)商緩存

協(xié)商緩存是由服務(wù)器來確定緩存資源是否可用。 主要涉及到兩對屬性字段边器,都是成對出現(xiàn)的训枢,即第一次請求的響應(yīng)頭帶上某個字, Last-Modified 或者 Etag,則后續(xù)請求則會帶上對應(yīng)的請求字段 If-Modified-Since或者 If-None-Match忘巧,若響應(yīng)頭沒有 Last-Modified 或者 Etag 字段恒界,則請求頭也不會有對應(yīng)的字段。

  • Last-Modified/If-Modified-Since 二者的值都是 GMT 格式的時間字符串砚嘴, Last-Modified 標(biāo)記最后文件修改時間十酣, 下一次請求時,請求頭中會帶上 If-Modified-Since 值就是 Last-Modified 告訴服務(wù)器我本地緩存的文件最后修改的時間际长,在服務(wù)器上根據(jù)文件的最后修改時間判斷資源是否有變化耸采, 如果文件沒有變更則返回 304 Not Modified ,請求不會返回資源內(nèi)容也颤,瀏覽器直接使用本地緩存洋幻。當(dāng)服務(wù)器返回 304 Not Modified 的響應(yīng)時,response header 中不會再添加的 Last-Modified 去試圖更新本地緩存的 Last-Modified翅娶, 因為既然資源沒有變化文留,那么 Last-Modified 也就不會改變好唯;如果資源有變化,就正常返回返回資源內(nèi)容燥翅,新的 Last-Modified 會在 response header 返回骑篙,并在下次請求之前更新本地緩存的 Last-Modified,下次請求時森书,If-Modified-Since會啟用更新后的 Last-Modified靶端。

  • Etag/If-None-Match, 值都是由服務(wù)器為每一個資源生成的唯一標(biāo)識串凛膏,只要資源有變化就這個值就會改變杨名。服務(wù)器根據(jù)文件本身算出一個哈希值并通過 ETag字段返回給瀏覽器,接收到 If-None-Match 字段以后猖毫,服務(wù)器通過比較兩者是否一致來判定文件內(nèi)容是否被改變台谍。與 Last-Modified 不一樣的是,當(dāng)服務(wù)器返回 304 Not Modified 的響應(yīng)時吁断,由于在服務(wù)器上ETag 重新計算過趁蕊,response header中還會把這個 ETag 返回,即使這個 ETag 跟之前的沒有變化仔役。

HTTP 中并沒有指定如何生成 ETag掷伙,可以由開發(fā)者自行生成,哈希是比較理想的選擇又兵。

為什么要有 Etag

HTTP1.1Etag 的出現(xiàn)主要是為了解決幾個 Last-Modified 比較難解決的問題:

  • 一些文件也許會周期性的更改任柜,但是內(nèi)容并不改變(僅僅改變的修改時間),這個時候我們并不希望客戶端認(rèn)為這個文件被修改了寒波,而重新 GET乘盼;
  • 某些文件修改非常頻繁,比如在秒以下的時間內(nèi)進(jìn)行修改俄烁,(比方說 1s 內(nèi)修改了 N 次)绸栅,If-Modified-Since 能檢查到的粒度是秒級的,使用 Etag 就能夠保證這種需求下客戶端在 1 秒內(nèi)能刷新 N 次 cache页屠。
  • 某些服務(wù)器不能精確的得到文件的最后修改時間粹胯。

優(yōu)先級

 Cache-Control  > expires > Etag > Last-Modified

用戶行為對緩存的影響

簡單說就是 F5 刷新的時候,會暫時禁用強緩存

經(jīng)過對 qq辰企、fire fox 风纠、safari 、chrome 這幾個瀏覽器的訪問同一個頁面測試我發(fā)現(xiàn)牢贸,不同的瀏覽器在 F5 刷新的時候 竹观,同一個文件 qq 、fire fox 瀏覽器會返回 304 Not Nodified,在請求頭中不攜帶 Expires/Cache-Control臭增; 而 chrome 和 safari 刷新的時候懂酱,會返回 200 from cache, 沒有真正發(fā)起請求誊抛,走強緩存列牺。可見不同的瀏覽器反饋是不一致的拗窃,所以下面表格中"F5 刷新"時 Expires/Cache-Control 會無效我認(rèn)為是存在一定爭議的瞎领。

而 Ctrl + F5 強制刷新的時候,會暫時禁用強緩存和協(xié)商緩存随夸。

在寫這篇博客時九默,對于我僅僅測試了一個瀏覽器之后便寫了無效(因為網(wǎng)上大多數(shù)帖子寫了無效,我也以為我驗證通過了)逃魄,對指出這個問題的群友荤西,表示感謝,希望其他人不會被我誤導(dǎo)伍俘。

用戶操作 Expires/Cache-Control Last-Modied/Etag
地址欄回車 有效 有效
頁面鏈接跳轉(zhuǎn) 有效 有效
新開窗口 有效 有效
前進(jìn)回退 有效 有效
F5 刷新 無效(有爭議,不同瀏覽器反饋不一致) 有效
Ctrl+F5 強制刷新 無效 無效

如何設(shè)置強緩存和協(xié)商緩存

  1. 后端服務(wù)器勉躺,寫入代碼邏輯中:

    res.setHeader('max-age': '3600 public')
    res.setHeader(etag: '5c20abbd-e2e8')
    res.setHeader('last-modified': Mon, 24 Dec 2018 09:49:49 GMT)
    
  2. Nginx 配置

    add_header Cache-Control "max-age=3600"
    

    一般來說癌瘾,通過 nginx 靜態(tài)資源服務(wù)器,會默認(rèn)給資源帶上強緩存饵溅、協(xié)商緩存的 header 字段妨退。

    [圖片上傳失敗...(image-beeb56-1580376444420)]

兩個示例

  1. 如果在 cache-control定義的 max-age 時間之內(nèi),js, css 文件會走強緩存蜕企,http 狀態(tài)碼是 200咬荷, 跟服務(wù)器也并不會有交互。但是第一個文件 index.html 文件, 每次回車或者刷新都是狀態(tài)碼都是 304 轻掩,因為它的請求頭中默認(rèn)每次都攜帶了 Cache-Control: max-age=0 幸乒。

    [圖片上傳失敗...(image-acbcab-1580376444420)]

    [圖片上傳失敗...(image-6f9b34-1580376444420)]

  2. js css 文件 cache-control 超時之后,重新按回車會走協(xié)商緩存唇牧,請求服務(wù)器發(fā)現(xiàn)資源沒有改變罕扎,于是返回 304 ,瀏覽器從緩存中獲取內(nèi)容丐重,從 size 中也可以看出端倪腔召, 幾百 B 的包不是靜態(tài)資源的體積。

    [圖片上傳失敗...(image-882bd2-1580376444420)]

三級緩存原理(大白話)

最后總結(jié)一下瀏覽器的三級緩存原理:

  1. 先去內(nèi)存看扮惦,如果有臀蛛,直接加載

  2. 如果內(nèi)存沒有,擇取硬盤獲取,如果有直接加載

  3. 如果硬盤也沒有浊仆,那么就進(jìn)行網(wǎng)絡(luò)請求

  4. 加載到的資源緩存到硬盤和內(nèi)存

參考文檔

from disk cache 與 from memory cache

http 協(xié)商緩存 VS 強緩存

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末客峭,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子氧卧,更是在濱河造成了極大的恐慌桃笙,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,378評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件沙绝,死亡現(xiàn)場離奇詭異搏明,居然都是意外死亡,警方通過查閱死者的電腦和手機闪檬,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評論 2 382
  • 文/潘曉璐 我一進(jìn)店門星著,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人粗悯,你說我怎么就攤上這事虚循。” “怎么了样傍?”我有些...
    開封第一講書人閱讀 152,702評論 0 342
  • 文/不壞的土叔 我叫張陵横缔,是天一觀的道長。 經(jīng)常有香客問我衫哥,道長茎刚,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,259評論 1 279
  • 正文 為了忘掉前任撤逢,我火速辦了婚禮膛锭,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘蚊荣。我一直安慰自己初狰,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 64,263評論 5 371
  • 文/花漫 我一把揭開白布互例。 她就那樣靜靜地躺著奢入,像睡著了一般。 火紅的嫁衣襯著肌膚如雪敲霍。 梳的紋絲不亂的頭發(fā)上俊马,一...
    開封第一講書人閱讀 49,036評論 1 285
  • 那天,我揣著相機與錄音肩杈,去河邊找鬼柴我。 笑死,一個胖子當(dāng)著我的面吹牛扩然,可吹牛的內(nèi)容都是我干的艘儒。 我是一名探鬼主播,決...
    沈念sama閱讀 38,349評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼界睁!你這毒婦竟也來了觉增?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,979評論 0 259
  • 序言:老撾萬榮一對情侶失蹤翻斟,失蹤者是張志新(化名)和其女友劉穎逾礁,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體访惜,經(jīng)...
    沈念sama閱讀 43,469評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡嘹履,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,938評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了债热。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片砾嫉。...
    茶點故事閱讀 38,059評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖窒篱,靈堂內(nèi)的尸體忽然破棺而出焕刮,到底是詐尸還是另有隱情,我是刑警寧澤墙杯,帶...
    沈念sama閱讀 33,703評論 4 323
  • 正文 年R本政府宣布配并,位于F島的核電站,受9級特大地震影響高镐,放射性物質(zhì)發(fā)生泄漏荐绝。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,257評論 3 307
  • 文/蒙蒙 一避消、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧召夹,春花似錦岩喷、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至鲸阔,卻和暖如春偷霉,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背褐筛。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工类少, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人渔扎。 一個月前我還...
    沈念sama閱讀 45,501評論 2 354
  • 正文 我出身青樓硫狞,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子残吩,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,792評論 2 345

推薦閱讀更多精彩內(nèi)容