淺解強緩存和協商緩存

本文全部代碼皆採用express搭建的簡單服務器css

web緩存描述 :

Web 緩存是能夠自動保存常見文檔副本的 HTTP 設備。當 Web 請求抵達緩存時, 若是本地有「已緩存的」副本,就能夠從本地存儲設備而不是原始服務器中提取這 個文檔。(此結論來自http權威指南)html

緩存的優缺點:

優勢:web

  • 緩存減小了冗餘的數據傳輸,節省了你的網絡費用。
  • 緩存緩解了網絡瓶頸的問題。不須要更多的帶寬就可以更快地加載頁面。
  • 緩存下降了對原始服務器的要求。服務器能夠更快地響應,避免過載的出現。
  • 緩存下降了距離時延,由於從較遠的地方加載頁面會更慢一些。

缺點:express

  • 緩存中的數據可能與服務器的數據不一致;
  • 消耗內存;
緩存驗證概述:
緩存可分爲強緩存和協商緩存。

1,瀏覽器進行資源請求時,會判斷response headers是否命中強緩存,若是命中,直接從本地讀取緩存,不會向服務器發送請求,
2,當強緩存沒有命中時,會發送請求到服務端,判斷協商緩存是否命中,若是命中,服務器將請求返回,不會返回資源,告訴瀏覽器從本地讀取緩存。如何不命中,服務器直接返回資源
區別: 強緩存命中,不會請求服務器,直接請求緩存;協商緩存命中,會請求服務器,不會返回內容,而後讀取緩存;

緩存的處理流程

from memory cache 和 from disk cache的區別

from memory cache:字面理解是從內存中,其實也是字面的含義,這個資源是直接從內存中拿到的,不會請求服務器通常已經加載過該資源且緩存在了內存當中,當關閉該頁面時,此資源就被內存釋放掉了,再次從新打開相同頁面時不會出現from memory cache的狀況瀏覽器

from disk cache:同上相似,此資源是從磁盤當中取出的,也是在已經在以前的某個時間加載過該資源,不會請求服務器可是此資源不會隨着該頁面的關閉而釋放掉,由於是存在硬盤當中的,下次打開仍會from disk cache (來自:blog.csdn.net/garrettzxd/…緩存

如下是緩存實現的四種方式

強緩存

強緩存又分爲Expires 和 Cache-Control

Expires,該值是一個GMT時間格式個字符串,瀏覽器進行第一次請求時,服務器會在返回頭部加上Expires,下次請求,若是在這個時間以前則命中緩存,bash

app.get('/', (req, res) => {
    const cssContent = path.join(__dirname, './html/index.html');
    fs.readFile(cssContent, function(err, data) {
          res.setHeader("Expires", new Date(Date.now() + 2592000000).toUTCString());
        res.end(data);
    })
});

複製代碼

Cache-Control ,該值是利用max-age判斷緩存的生命週期,是以秒爲單位,如何在生命週期時間內,則命中緩存服務器

app.get('/', (req, res) => {
    const cssContent = path.join(__dirname, './html/index.html');
    fs.readFile(cssContent, function(err, data) {
        res.setHeader("Cache-Control", "max-age=0");
        res.end(data);
    })
});

複製代碼

命中緩存: 網絡

協商緩存

協商緩存利用Last-Modified , If-Modified-Since 和 ETag , If-None-Match來實現
Last-Modified , If-Modified-Since

Last-Modified: 表示爲爲實體頭部部分,response返回,表示爲資源的最後更新時間
If-Modified-Since:經過比較兩次的時間判斷,資源在請求期間是否有修改,假如沒有修改,則命中協商緩存,瀏覽器從緩存中讀取資源,若是沒有命中,資源有過修改,返回新的Last-Modified時間和服務器資源app

app.get('/', (req, res) => {
    const cssContent = path.join(__dirname, './html/index.html')
    fs.stat(cssContent, (err, start) => {
        if (req.headers['if-modified-since'] === start.mtime.toUTCString()) {
            res.writeHead(304, 'Not Modified');
            res.end();
        } else {
            fs.readFile(cssContent, function (err, data) {
                let lastModified = start.mtime.toUTCString();
                res.setHeader('Last-Modified', lastModified);
                res.writeHead(200, 'OK');
                res.end(data);
            })
        }
    })

});
複製代碼
ETag , If-None-Match

有些狀況下僅判斷最後修改日期來驗證資源是否有改動是不夠的:
1,存在週期性重寫某些資源,但資源實際包含的內容並沒有變化;
2,被修改的信息並不重要,如註釋等;
3,Last-Modified沒法精確到毫秒,但有些資源更新頻率有時會小於一秒。

ETag:爲相應頭部字段,表示資源內容的惟一標識,隨服務器response返回;
If-None-Match: 服務器比較請求頭中的If-None-Match和當前資源中的etag是否一致,來判斷資源是否修改過,若是沒有修改,則命中緩存,瀏覽器從緩存中讀取資源,若是修改過,服務器會返回新的etag,並返回資源;

app.get('/home', (req, res) => {
    const cssContent = path.join(__dirname, './html/index.html')
    fs.stat(cssContent, (err, start) => {
        let etag = md5(cssContent);
        if (req.headers['if-none-match'] === etag) {
            res.writeHead(304, 'Not Modified');
            res.end();
        } else {
            fs.readFile(cssContent, function (err, data) {
                res.setHeader('Etag', etag);
                res.writeHead(200, 'OK');
                res.end(data);
            })
        }
    })
});
複製代碼

不推薦使用 Expires 首部,它指定的是實際的過時日期而不是秒數。HTTP 設計者 後來認爲,因爲不少服務器的時鐘都不一樣步,或者不正確,因此最好仍是用剩餘秒 數,而不是絕對時間來表示過時時間。

ETag解決了Last-Modified使用時可能出現的資源的時間戳變了但內容沒變及若是再一秒鐘之內資源變化但Last-Modified沒變的問題,感受ETag更加穩妥。

補充:根據瀏覽器緩存策略,Expire和Cache-Control用回車、後退、F5刷新會跳過本地緩存,每次都會從服務器中獲數據。

相關文章
相關標籤/搜索