1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        圖解 HTTP 緩存

        共 4374字,需瀏覽 9分鐘

         ·

        2021-10-04 06:32

        點擊上方“服務(wù)端思維”,選擇“設(shè)為星標(biāo)

        回復(fù)”669“獲取獨家整理的精選資料集

        回復(fù)”加群“加入全國服務(wù)端高端社群「后端圈」


        f37fbf84889e9e43d289a8d1a0e2a092.webp

        作者 | 句號出品?| 政采云前端團(tuán)隊

        前言

        HTTP 的緩存機(jī)制,可以說這是前端工程師需要掌握的重要知識點之一。本文將針對 HTTP 緩存整體的流程做一個詳細(xì)的講解,爭取做到大家讀完整篇文章后,對緩存有一個整體的了解。

        HTTP 緩存分為 2 種,一種是強(qiáng)緩存,另一種是協(xié)商緩存。主要作用是可以加快資源獲取速度,提升用戶體驗,減少網(wǎng)絡(luò)傳輸,緩解服務(wù)端的壓力。這是緩存運(yùn)作的一個整體流程圖:b569a3767996c389e4dbca10a5eacbb3.webpHttp緩存.jpg

        強(qiáng)緩存

        不需要發(fā)送請求到服務(wù)端,直接讀取瀏覽器本地緩存,在 Chrome 的 Network 中顯示的 HTTP 狀態(tài)碼是 200 ,在 Chrome 中,強(qiáng)緩存又分為 Disk Cache(存放在硬盤中)和 Memory Cache(存放在內(nèi)存中),存放的位置是由瀏覽器控制的。是否強(qiáng)緩存由 Expires、Cache-Control 和 Pragma 3 個 Header 屬性共同來控制。

        ○ Expires

        Expires 的值是一個 HTTP 日期,在瀏覽器發(fā)起請求時,會根據(jù)系統(tǒng)時間和 Expires 的值進(jìn)行比較,如果系統(tǒng)時間超過了 Expires 的值,緩存失效。由于和系統(tǒng)時間進(jìn)行比較,所以當(dāng)系統(tǒng)時間和服務(wù)器時間不一致的時候,會有緩存有效期不準(zhǔn)的問題。Expires 的優(yōu)先級在三個 Header 屬性中是最低的。

        ○ Cache-Control

        Cache-Control 是 HTTP/1.1 中新增的屬性,在請求頭和響應(yīng)頭中都可以使用,常用的屬性值如有:

        • max-age:單位是秒,緩存時間計算的方式是距離發(fā)起的時間的秒數(shù),超過間隔的秒數(shù)緩存失效
        • no-cache:不使用強(qiáng)緩存,需要與服務(wù)器驗證緩存是否新鮮
        • no-store:禁止使用緩存(包括協(xié)商緩存),每次都向服務(wù)器請求最新的資源
        • private:專用于個人的緩存,中間代理、CDN 等不能緩存此響應(yīng)
        • public:響應(yīng)可以被中間代理、CDN 等緩存
        • must-revalidate:在緩存過期前可以使用,過期后必須向服務(wù)器驗證

        ○ Pragma

        Pragma 只有一個屬性值,就是 no-cache ,效果和 Cache-Control 中的 no-cache 一致,不使用強(qiáng)緩存,需要與服務(wù)器驗證緩存是否新鮮,在 3 個頭部屬性中的優(yōu)先級最高。

        本地通過 express 起一個服務(wù)來驗證強(qiáng)緩存的 3 個屬性,代碼如下:
        const?express?=?require('express');
        const?app?=?express();
        var?options?=?{?
        ??etag:?false,?//?禁用協(xié)商緩存
        ??lastModified:?false,?//?禁用協(xié)商緩存
        ??setHeaders:?(res,?path,?stat)?=>?{
        ????res.set('Cache-Control',?'max-age=10');?//?強(qiáng)緩存超時時間為10秒
        ??},
        };
        app.use(express.static((__dirname?+?'/public'),?options));
        app.listen(3000);

        第一次加載,頁面會向服務(wù)器請求數(shù)據(jù),并在 Response Header 中添加 Cache-Control ,過期時間為 10 秒。

        48e44b06eee451c92793947838a9678c.webp緩存1.jpg第二次加載,Date 頭屬性未更新,可以看到瀏覽器直接使用了強(qiáng)緩存,實際沒有發(fā)送請求。88c1c3789dd0223e89e91245c9c47ab3.webp緩存2.jpg過了 10 秒的超時時間之后,再次請求資源:63391bf3c952f861958c37cf956a5223.webp緩存3.jpg當(dāng) Pragma 和 Cache-Control 同時存在的時候,Pragma 的優(yōu)先級高于 Cache-Control。78049ef013fa6e6652a6d498c8e8b525.webp緩存5.jpg

        協(xié)商緩存

        當(dāng)瀏覽器的強(qiáng)緩存失效的時候或者請求頭中設(shè)置了不走強(qiáng)緩存,并且在請求頭中設(shè)置了If-Modified-Since 或者 If-None-Match 的時候,會將這兩個屬性值到服務(wù)端去驗證是否命中協(xié)商緩存,如果命中了協(xié)商緩存,會返回 304 狀態(tài),加載瀏覽器緩存,并且響應(yīng)頭會設(shè)置 Last-Modified 或者 ETag 屬性。

        ○ ETag/If-None-Match

        ETag/If-None-Match 的值是一串 hash 碼,代表的是一個資源的標(biāo)識符,當(dāng)服務(wù)端的文件變化的時候,它的 hash碼會隨之改變,通過請求頭中的 If-None-Match 和當(dāng)前文件的 hash 值進(jìn)行比較,如果相等則表示命中協(xié)商緩存。ETag 又有強(qiáng)弱校驗之分,如果 hash 碼是以 "W/" 開頭的一串字符串,說明此時協(xié)商緩存的校驗是弱校驗的,只有服務(wù)器上的文件差異(根據(jù) ETag 計算方式來決定)達(dá)到能夠觸發(fā) hash 值后綴變化的時候,才會真正地請求資源,否則返回 304 并加載瀏覽器緩存。

        ○ Last-Modified/If-Modified-Since

        Last-Modified/If-Modified-Since 的值代表的是文件的最后修改時間,第一次請求服務(wù)端會把資源的最后修改時間放到 Last-Modified 響應(yīng)頭中,第二次發(fā)起請求的時候,請求頭會帶上上一次響應(yīng)頭中的 Last-Modified 的時間,并放到 If-Modified-Since 請求頭屬性中,服務(wù)端根據(jù)文件最后一次修改時間和 If-Modified-Since 的值進(jìn)行比較,如果相等,返回 304 ,并加載瀏覽器緩存。

        本地通過 express 起一個服務(wù)來驗證協(xié)商緩存,代碼如下:
        const?express?=?require('express');
        const?app?=?express();
        var?options?=?{?
        ??etag:?true,?//?開啟協(xié)商緩存
        ??lastModified:?true,?//?開啟協(xié)商緩存
        ??setHeaders:?(res,?path,?stat)?=>?{
        ????res.set({
        ??????'Cache-Control':?'max-age=00',?//?瀏覽器不走強(qiáng)緩存
        ??????'Pragma':?'no-cache',?//?瀏覽器不走強(qiáng)緩存
        ????});
        ??},
        };
        app.use(express.static((__dirname?+?'/public'),?options));
        app.listen(3001);

        第一次請求資源:

        0a9b15bf1679b1d0768f4bfac6a44a06.webp緩存6.jpg第二次請求資源,服務(wù)端根據(jù)請求頭中的 If-Modified-Since 和 If-None-Match 驗證文件是否修改。8707955be484a08c0e2194a2dc358b25.webp緩存7.jpg

        我們再來驗證一下 ETag 在強(qiáng)校驗的情況下,只增加一行空格,hash 值如何變化,在代碼中,我采用的是對文件進(jìn)行 MD5 加密來計算其 hash 值。

        注:只是為了演示用,實際計算不是通過 MD5 加密的,Apache 默認(rèn)通過 FileEtag 中 FileEtag INode Mtime Size 的配置自動生成 ETag,用戶可以通過自定義的方式來修改文件生成 ETag 的方式。

        為了保證 lastModified 不影響緩存,我把通過 Last-Modified/If-Modified-Since 請求頭刪除了,源碼如下:
        const?express?=?require('express');
        const?CryptoJS?=?require('crypto-js/crypto-js');
        const?fs?=?require('fs');
        const?app?=?express();
        var?options?=?{?
        ??etag:?true,?//?只通過Etag來判斷
        ??lastModified:?false,?//?關(guān)閉另一種協(xié)商緩存
        ??setHeaders:?(res,?path,?stat)?=>?{
        ????const?data?=?fs.readFileSync(path,?'utf-8');?//?讀取文件
        ????const?hash?=?CryptoJS.MD5((JSON.stringify(data)));?//?MD5加密
        ????res.set({
        ??????'Cache-Control':?'max-age=00',?//?瀏覽器不走強(qiáng)緩存
        ??????'Pragma':?'no-cache',?//?瀏覽器不走強(qiáng)緩存
        ??????'ETag':?hash,?//?手動設(shè)置Etag值為MD5加密后的hash值
        ????});
        ??},
        };
        app.use(express.static((__dirname?+?'/public'),?options));
        app.listen(4000);?//?使用新端口號,否則上面驗證的協(xié)商緩存會一直存在

        第一次和第二次請求如下:

        2afa09093e73eb30812c2c015289e642.webp緩存10.jpgfb53a8778af4e27edf0c43a9871fc75e.webp緩存11.jpg然后我修改了 test.js ,增加一個空格后再刪除一個空格,保持文件內(nèi)容不變,但文件的修改時間改變,發(fā)起第三次請求,由于我生成 ETag 的方式是通過對文件內(nèi)容進(jìn)行 MD5 加密生成,所以雖然修改時間變化了,但請求依然返回了 304,讀取瀏覽器緩存。fd75950addbb2d7c7eecbbcde447a1f5.webp緩存13.jpg

        ETag/If-None-Match 的出現(xiàn)主要解決了 Last-Modified/If-Modified-Since 所解決不了的問題:

        • 如果文件的修改頻率在秒級以下,Last-Modified/If-Modified-Since 會錯誤地返回 304
        • 如果文件被修改了,但是內(nèi)容沒有任何變化的時候,Last-Modified/If-Modified-Since 會錯誤地返回 304,上面的例子就說明了這個問題

        總結(jié)

        在實際使用場景中,比如政采云的官網(wǎng)。圖片、不常變化的 JS 等靜態(tài)資源都會使用緩存來提高頁面的加載速度。例如政采云首頁的頂部導(dǎo)航欄,埋點 SDK 等等。

        在文章的最后,我們再次回到這張流程圖,這張圖涵蓋了 HTTP 緩存的整體流程,大家對整體流程熟悉后,也可以自己動手通過 Node 來驗證下 HTTP 緩存。b569a3767996c389e4dbca10a5eacbb3.webpHttp緩存.jpg

        — 本文結(jié)束 —


        f874e0aa2e314369954488b869d69ef7.webp

        ●?漫談設(shè)計模式在 Spring 框架中的良好實踐

        ●?顛覆微服務(wù)認(rèn)知:深入思考微服務(wù)的七個主流觀點

        ●?人人都是 API 設(shè)計者

        ●?一文講透微服務(wù)下如何保證事務(wù)的一致性

        ●?要黑盒測試微服務(wù)內(nèi)部服務(wù)間調(diào)用,我該如何實現(xiàn)?



        關(guān)注我,回復(fù) 「加群」 加入各種主題討論群。



        對「服務(wù)端思維」有期待,請在文末點個在看

        喜歡這篇文章,歡迎轉(zhuǎn)發(fā)、分享朋友圈


        14d2f93784ad93880ab0a9d5a6d4d13f.webp在看點這里d6cebb8f915036070edb3bc1998b65f0.webp
        瀏覽 33
        點贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            中文一区在线 | 韩国一级片中文 | 丁香花电影高清在线小说阅读 | 日日擼夜夜擼狠狠擼88 | 夜夜嗨av一区二区三区四区 | 农村妇女做爰视频 | 日逼视屏 | 男女视频观看 | 免费一级A片在线观看视频 | 成人午夜福利影视 |