1. 程式人生 > 程式設計 >node.js實現http伺服器與瀏覽器之間的內容快取操作示例

node.js實現http伺服器與瀏覽器之間的內容快取操作示例

本文例項講述了node.js實現http伺服器與瀏覽器之間的內容快取操作。分享給大家供大家參考,具體如下:

一、快取的作用

1、減少了資料傳輸,節約流量。

2、減少伺服器壓力,提高伺服器效能。

3、加快客戶端載入頁面的速度。

二、快取的分類

1、強制快取,如果快取有效,則不需要與伺服器發生互動,直接使用快取。

2、對比快取,每次都需要與伺服器發生互動,對快取進行比較判斷是否可以使用快取。

三、通過使用 Last-Modified / If-Modified-Since 來進行快取判斷

1、Last-Modified 是伺服器向客戶端傳送的頭資訊,用於告訴客戶端資源的 最後修改時間,該資訊瀏覽器會儲存起來。

2、If-Modified-Since 是客戶端向伺服器傳送的頭資訊,當客戶端再次請求資源時,瀏覽器會帶上該資訊傳送給伺服器,伺服器通過該資訊來判斷資源是否過期。

3、如果沒有過期,則響應 304 表示 未更新,告訴瀏覽器使用儲存的快取。

4、如果過期了,則響應 200,返回最新的資源。

const http = require('http');
const url = require('url');
const path = require('path');
const fs = require('fs');
const util = require('util');
const mime = require('mime');
//建立http伺服器並監聽埠
let server = http.createServer();
server.listen(1234,'0.0.0.0',function () {
  console.log('開始監聽');
});
function sendFile(req,res,filePath,stats) {
  //設定檔案內容型別
  res.setHeader('Content-Type',mime.getType(filePath));
  //設定資源最後修改時間頭資訊
  res.setHeader('Last-Modified',stats.ctime.toGMTString());
  //通過管道將檔案資料傳送給客戶端
  fs.createReadStream(filePath).pipe(res);
}
server.on('request',function (req,res) {
  let {pathname} = url.parse(req.url,true);
  //獲取檔案真實路徑
  let filePath = path.join(__dirname,pathname);
  //判斷檔案是否存在
  fs.stat(filePath,function (err,stats) {
    if (err) {
      return res.end(util.inspect(err));
    }
    if (!stats.isFile()) {
      return res.end('is not file');
    }
    //獲取客戶端請求的If-Modified-Since頭資訊
    let ifModifiedSince = req.headers['if-modified-since'];
    if (ifModifiedSince) {
      //如果最後修改時間相同,說明該資源並未修改,直接響應 304,讓瀏覽器從快取中獲取資料。
      if (ifModifiedSince == stats.ctime.toGMTString()) {
        res.statusCode = 304;
        res.end();
      } else {
        sendFile(req,stats);
      }
    } else {
      sendFile(req,stats);
    }
  });
});

通過最後修改時間判斷快取是否可用,並不是很精確,有如下幾個問題:

1、Last-Modified 只精確到秒,秒以下的時間修改,將無法準確判斷。

2、檔案最後修改時間變了,但 內容並沒有發生改變。

3、檔案存在於多個 CDN 上,那該檔案的最後修改時間是不一樣的。

四、通過 ETag / If-None-Match 進行判斷

ETag 表示 實體標籤,將內容通過 hash 演算法生成一段字串,用以標識資源,如果資源發生變化,則 ETag 也會變化。

ETag 是伺服器生成的,傳送給客戶端的。

1、客戶端請求資源,伺服器根據資源生成ETag,傳送給客戶端。瀏覽器會儲存該資訊。

2、當客戶端再次請求時,瀏覽器會發送 If-None-Match 給伺服器,值為第1步儲存的資訊,伺服器通過該資訊進行判斷,資源是否修改過。

3、如果沒有修改過,則響應 304 未更新,告訴瀏覽器使用儲存的快取。

4、如果修改過,則響應 200,返回最新資源。

const http = require('http');
const url = require('url');
const path = require('path');
const fs = require('fs');
const util = require('util');
const crypto = require('crypto');
const mime = require('mime');
//建立http伺服器並監聽埠
let server = http.createServer();
server.listen(1234,eTag) {
  //設定檔案內容型別
  res.setHeader('Content-Type',mime.getType(filePath));
  //設定ETag頭資訊
  res.setHeader('ETag',eTag);
  //通過管道將檔案資料傳送給客戶端
  fs.createReadStream(filePath).pipe(res);
}
server.on('request',stats) {
    if (err) {
      return res.end(util.inspect(err));
    }
    if (!stats.isFile()) {
      return res.end('is not file');
    }
    //獲取客戶端請求的If-None-Match頭資訊
    let ifNoneMatch = req.headers['if-none-match'];
    //建立可讀流
    let rs = fs.createReadStream(filePath);
    //建立md5演算法
    let md5 = crypto.createHash('md5');
    rs.on('data',function (data) {
      md5.update(data);
    });
    rs.on('end',function () {
      let eTag = md5.digest('hex');
      if (ifNoneMatch) {
        //判斷eTag與客戶端傳送過來的If-None-Match是否相等
        if (ifNoneMatch == eTag) {
          res.statusCode = 304;
          res.end();
        } else {
          sendFile(req,eTag);
        }
      } else {
        sendFile(req,eTag);
      }
    });
  });
});

五、讓瀏覽器在快取有效期內不用發請求

Expires 是http1.0的內容,用於設定快取的有效期,在有效期內瀏覽器直接從瀏覽器快取中獲取資料。

Cache-Control 與Expires作用一樣,是http1.1的內容,用於指明當前資源的有效期,優先順序高於Expires。

Cache-Control可以設定的值 :

1、private 客戶端可以快取

2、public 客戶端和代理伺服器都可以快取

3、max-age=10 快取內容在10秒後失效

4、no-cache 使用對比快取驗證,強制向伺服器驗證

5、no-store 內容都不快取,強制快取和對比快取都不會觸發

const http = require('http');
const url = require('url');
const path = require('path');
const fs = require('fs');
const util = require('util');
const mime = require('mime');
//建立http伺服器並監聽埠
let server = http.createServer();
server.listen(1234,mime.getType(filePath));
  //設定快取失效時間60秒
  res.setHeader('Expires',new Date(Date.now() + 60 * 1000).toUTCString());
  //設定快取失效時間60秒
  res.setHeader('Cache-Control','max-age=60');
  //通過管道將檔案資料傳送給客戶端
  fs.createReadStream(filePath).pipe(res);
}
server.on('request',stats) {
    if (err) {
      return res.end(util.inspect(err));
    }
    if (!stats.isFile()) {
      return res.end('is not file');
    }
    sendFile(req,stats)
  });
});

希望本文所述對大家node.js程式設計有所幫助。