天天看點

NodeJS -- 浏覽器緩存機制

 浏覽器緩存機制

上面是浏覽器的緩存機制,如果不清楚的小夥伴可以去瞧瞧。

我們來簡單用代碼試試。

協商緩存

我們先試一下協商緩存的last-modified

我們簡單的使用http協定建立一個伺服器,然後在public目錄下面存放一些資源(一個html,一個css)。我們通路html檔案。

我們使用Last-modified屬性,儲存的是html檔案最後的修改的時間.toUTCString(),浏覽器知道我們的響應請求頭裡面有Last-Modified屬性,那麼下一次發送請求時就會帶上一個If-Modified-Since屬性,值就是上一次的伺服器傳回的。那麼伺服器就應該用目前的檔案最後的修改的時間.toUTCString()與它比對,如果相等,那麼我們就隻需要傳回304,不相等就傳回目前最新的檔案,并且發送Last-Modified

const http = require("http");
const chalk = require("chalk");
const url = require("url");
const mime = require('mime');
const fs = require("fs");
const path = require("path");
const { promisify } = require("util");

const stat = promisify(fs.stat);

const server = http.createServer(async function (req, res) {
     const { pathname } = url.parse(req.url);
     const filename = path.join(process.cwd(), pathname);
     
     try {
        const status = await stat(filename);
        if (req.headers["if-modified-since"] === status.ctime.toUTCString()) {//比對成功
           res.writeHead(304);
           res.end();
            return ;
        }
        res.setHeader("Content-Type", mime.getType(filename));
        res.setHeader("Last-Modified", status.ctime.toUTCString());
        fs.createReadStream(filename).pipe(res);

     } catch (err) {
         console.log(err);//檔案夾出現問題
     }
})

server.listen(8080, () => {
    console.log(`${chalk.red("伺服器已經啟動")}`);
});
server.on("close", () => {
    console.log(`${chalk.green("伺服器已經關閉")}`);
})
           

我們試試看,通路index.html

第一次通路:

NodeJS -- 浏覽器緩存機制

第二次通路:

NodeJS -- 浏覽器緩存機制

修改html檔案,儲存,然後通路:

NodeJS -- 浏覽器緩存機制

下面我們介紹ETag字段,不過在此之前,我們必須要先想想為什麼還需要ETag字段,前面Last-Modified字段感覺已經很完美了。

1:使用Last-Modifie的前提在于,我們可以精确的擷取的檔案的修改時間,如果這一點出現問題那麼就根本行不通了。

2:檔案的内容并沒有發生改變(我删除了一個字母,然後又加上,重新儲存),這樣也會導緻檔案修改時間改變。

3:

NodeJS -- 浏覽器緩存機制

檔案修改時間的機關是精度是秒,而當修改過于頻繁,在秒一下機關修改,那麼就會導緻檔案已經修改但是修改時間沒有變

4:如果了解CDN伺服器的小夥伴的同學知道,CDN伺服器緩存了一下靜态資源,但是每一個CDN伺服器儲存的檔案修改時間不一樣(因為CDN伺服器還是需要請求總的伺服器資源,這就導緻不同的伺服器會有不同的檔案修改時間),同樣的檔案在不同的CDN伺服器上面又不同的檔案最後修改時間,那麼就會導緻Last-Modified字段沒有作用。

ETag字段是儲存的一個檔案的摘要(通過hash函數計算出來的,隻要你的檔案改動了那麼這個值肯定就不一樣,比如md5)

const http = require("http");
const chalk = require("chalk");
const url = require("url");
const mime = require('mime');
const fs = require("fs");
const path = require("path");
const crypto = require("crypto");
const { promisify } = require("util");


const stat = promisify(fs.stat);

const server = http.createServer(async function (req, res) {
     const { pathname } = url.parse(req.url);
     const filename = path.join(process.cwd(), pathname);
     try {
        const status = await stat(filename);
        let etag;
        let data = fs.readFileSync(filename)
        etag = crypto.createHash("md5").update(data).digest("hex") //通過md5設定ETag字段
     
        if (req.headers["if-none-match"] ===  etag) {//比對成功
        console.log(etag);
           res.writeHead(304);
           res.end();
            return ;
        }
        res.setHeader("Content-Type", mime.getType(filename));
        res.setHeader("ETag", etag); //通過md5設定ETag字段
        fs.createReadStream(filename).pipe(res);
     } catch (err) {
         console.log(err);//檔案夾出現問題
     }
})

server.listen(8080, () => {
    console.log(`${chalk.red("伺服器已經啟動")}`);
});
server.on("close", () => {
    console.log(`${chalk.green("伺服器已經關閉")}`);
})
           

第一次通路:

NodeJS -- 浏覽器緩存機制

第二次通路:

NodeJS -- 浏覽器緩存機制

強制緩存

接下來試試Cache-Control的字段。通過上面的協商緩存,我們了解到協商緩存都需要與伺服器進行一次通信,那麼為了更加減少這次通信,我們有了強制緩存。

Cache-Control字段

  • public:所有内容都将被緩存(用戶端和代理伺服器都可緩存)
  • private:所有内容隻有用戶端可以緩存,Cache-Control的預設取值
  • no-cache:用戶端緩存内容,但是是否使用緩存則需要經過協商緩存來驗證決定
  • no-store:所有内容都不會被緩存,即不使用強制緩存,也不使用協商緩存
  • max-age=xxx (xxx is numeric):緩存内容将在xxx秒後失效

我們試試max-age值。

我們在HTML裡面引入了一個圖檔。

const http = require("http");
const chalk = require("chalk");
const url = require("url");
const mime = require('mime');
const fs = require("fs");
const path = require("path");
const crypto = require("crypto");
const { promisify } = require("util");


const stat = promisify(fs.stat);

const server = http.createServer(async function (req, res) {
     const { pathname } = url.parse(req.url);
     const filename = path.join(process.cwd(), pathname);
     console.log(filename);
     try {
        const status = await stat(filename);
        res.setHeader("Content-Type", mime.getType(filename));
        res.setHeader("Cache-Control", "max-age=30");  
        fs.createReadStream(filename).pipe(res);
     } catch (err) {
         console.log(err);//檔案夾出現問題
     }
})

server.listen(8080, () => {
    console.log(`${chalk.red("伺服器已經啟動")}`);
});
server.on("close", () => {
    console.log(`${chalk.green("伺服器已經關閉")}`);
})
           

第一次:

NodeJS -- 浏覽器緩存機制

第二次:

NodeJS -- 浏覽器緩存機制

Expires是HTTP1.0内容,通過上面的部落格,你應該知道這個字段的缺陷和與Cache-Control的差別。如果浏覽器預設為HTTP1.1,是以我就不示範了。

繼續閱讀