溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

HTTP緩存的作用和規(guī)則簡介

發(fā)布時間:2021-09-06 15:58:17 來源:億速云 閱讀:148 作者:chen 欄目:web開發(fā)

本篇內容介紹了“HTTP緩存的作用和規(guī)則簡介”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

前言

HTTP 緩存機制作為 Web 應用性能優(yōu)化的重要手段,對于從事 Web 開發(fā)的同學們來說,應該是知識體系的基礎環(huán)節(jié),也是想要成為前端架構的必備技能。

緩存的作用

我們?yōu)槭裁词褂镁彺?,是因為緩存可以給我們的 Web 項目帶來以下好處,以提高性能和用戶體驗。

  • 加快了瀏覽器加載網頁的速度;

  • 減少了冗余的數(shù)據(jù)傳輸,節(jié)省網絡流量和帶寬;

  • 減少服務器的負擔,大大提高了網站的性能。

由于從本地緩存讀取靜態(tài)資源,加快瀏覽器的網頁加載速度是一定的,也確實的減少了數(shù)據(jù)傳輸,就提高網站性能來說,可能一兩個用戶的訪問對于減小服務器的負擔沒有明顯效果,但如果這個網站在高并發(fā)的情況下,使用緩存對于減小服務器壓力和整個網站的性能都會發(fā)生質的變化。

緩存規(guī)則簡介

為了方便理解,我們認為瀏覽器存在一個緩存數(shù)據(jù)庫,用于存儲緩存信息(實際上靜態(tài)資源是被緩存到了內存和磁盤中),在瀏覽器第一次請求數(shù)據(jù)時,此時緩存數(shù)據(jù)庫沒有對應的緩存數(shù)據(jù),則需要請求服務器,服務器會將緩存規(guī)則和數(shù)據(jù)返回,瀏覽器將緩存規(guī)則和數(shù)據(jù)存儲進緩存數(shù)據(jù)庫。

HTTP緩存的作用和規(guī)則簡介

當瀏覽器地址欄輸入地址后請求的 index.html 是不會被緩存的,但 index.html 內部請求的其他資源會遵循緩存策略,HTTP 緩存有多種規(guī)則,根據(jù)是否需要向服務器發(fā)送請求主要分為兩大類,強制緩存和協(xié)商緩存。

強制緩存

1、強制緩存流程

強制緩存是第一次訪問服務器獲取數(shù)據(jù)后,在有效時間內不會再請求服務器,而是直接使用緩存數(shù)據(jù),強制緩存的流程如下。

HTTP緩存的作用和規(guī)則簡介

2、強制緩存判斷到期時間

那么如何判斷緩存是否到期呢?其實還是根據(jù)第一次訪問時服務器的響應頭來實現(xiàn)的,在 HTTP 1.0 版本和 HTTP 1.1 版本有所不同。

HTTP 1.0 版本,服務器使用的響應頭字段為 Expires,值為未來的絕對時間(時間戳),瀏覽器請求時的當前時間超過了 Expires 設置的時間,代表緩存失效,需要再次向服務器發(fā)送請求,否則都會直接從緩存數(shù)據(jù)庫中獲取數(shù)據(jù)。

HTTP 1.1 版本,服務器使用的響應頭字段為 Cache-Control,有多個值,意義各不相同。

  • private:客戶端可以緩存;

  • public:客戶端和代理服務器都可以緩存(對于前端而言,可以認為與 private 效果相同);

  • max-age=xxx:緩存的內容將在 xxx 秒后過期(相對時間,秒為單位);

  • no-cache:需要使用協(xié)商緩存(后面介紹)來驗證數(shù)據(jù)是否過期;

  • no-store:所有內容都不會緩存,強制緩存和協(xié)商緩存都不會觸發(fā)。

Cache-Control 的值中最常用的為 max-age=xxx,緩存本身就是為了數(shù)據(jù)傳輸?shù)膬?yōu)化和性能而存在的,所以 no-store 幾乎不會使用。

注意:在 HTTP 1.0 版本中,Expires 字段的絕對時間是從服務器獲取的,由于請求需要時間,所以瀏覽器的請求時間與服務器接收到請求所獲取的時間是存在誤差的,這也導致了緩存命中的誤差,在 HTTP 1.1 版本中,因為 Cache-Control 的值 max-age=xxx 中的 xxx 是以秒為單位的相對時間,所以在瀏覽器接收到資源后開始倒計時,規(guī)避了 HTTP 1.0 中緩存命中存在誤差的缺點,為了兼容低版本 HTTP 協(xié)議,正常開發(fā)中兩種響應頭會同時使用,HTTP 1.1 版本的實現(xiàn)優(yōu)先級高于 HTTP 1.0。

3、通過 Network 查看強制緩存

我們通過 Chrome 瀏覽器的開發(fā)者工具,打開 NetWork 查看強制緩存的相關信息。

HTTP緩存的作用和規(guī)則簡介

上面是百度網站 Logo 圖片的響應,我們可以清楚的看到,其中兼容了 HTTP 1.0HTTP 1.1 版本,并使用強制緩存存儲了 10 年。

下面看一看通過緩存取出的數(shù)據(jù)在 Network 中與其他資源的區(qū)別。

HTTP緩存的作用和規(guī)則簡介

其實緩存的儲存是內存和磁盤兩個位置,由當前瀏覽器本身的策略決定,比較隨機,從內存的緩存中取出的數(shù)據(jù)會顯示 (from memory cache),從磁盤的緩存中取出的數(shù)據(jù)會顯示 (from disk cache)。

4、NodeJS 服務器實現(xiàn)強制緩存

// 強制緩存
const http = require("http");
const url = require("url");
const path = require("path");
const mime = require("mime");
const fs = require("fs");

const server = http.createServer((req, res) => {
 let { pathname } = url.parse(req.url, true);
 pathname = pathname !== "/" ? pathname : "/index.html";

 // 獲取讀取文件的絕對路徑
 let p = path.join(__dirname, pathname);

 // 查看路徑是否合法
 fs.access(p, err => {
  // 路徑不合法則直接中斷連接
  if (err) return res.end("Not Found");

  // 設置強制緩存
  res.setHeader("Expires", new Date(Date.now() + 30000).toGMTString());
  res.setHeader("Cache-Control", "max-age=30");

  // 設置文件類型并響應給瀏覽器
  res.setHeader("Content-Type", `${mime.getType(p)};charset=utf8`);
  fs.createReadStream(p).pipe(res);
 });
});

server.listen(3000, () => {
 console.log("server start 3000");
});

上面 mime 模塊的 getType 方法可以成功返回傳入路徑下文件對應的文件類型,如 text/htmlapplication/javascript 等,是第三方模塊,使用之前需要安裝。

npm install mime

協(xié)商緩存

1、協(xié)商緩存流程

協(xié)商緩存又叫對比緩存,設置協(xié)商緩存后,第一次訪問服務器獲取數(shù)據(jù)時,服務器會將數(shù)據(jù)和緩存標識一起返回給瀏覽器,客戶端會將數(shù)據(jù)和標識存入緩存數(shù)據(jù)庫中,下一次請求時,會先去緩存中取出緩存標識發(fā)送給服務器進行詢問,當服務器數(shù)據(jù)更改時會更新標識,所以服務器拿到瀏覽器發(fā)來的標識進行對比,相同代表數(shù)據(jù)未更改,響應瀏覽器通知數(shù)據(jù)未更改,瀏覽器會去緩存中獲取數(shù)據(jù),如果標識不同,代表服務器更改過數(shù)據(jù),所以會將新的數(shù)據(jù)和新的標識返回瀏覽器,瀏覽器會將新的數(shù)據(jù)和標識存入緩存中,協(xié)商緩存的流程如下。

HTTP緩存的作用和規(guī)則簡介

協(xié)商緩存和強制緩存不同的是,協(xié)商緩存每次請求都需要跟服務器通信,而且命中緩存服務器返回狀態(tài)碼不再是 200,而是 304

2、協(xié)商緩存判斷標識

強制緩存是通過過期時間來控制是否訪問服務器,而協(xié)商緩存每次都要與服務器交互對比緩存標識,同樣的,對于協(xié)商緩存的實現(xiàn)在 HTTP 1.0 版本和 HTTP 1.1 版本也有所不同。

HTTP 1.0 版本中,服務器通過 Last-Modified 響應頭來設置緩存標識,通常取請求數(shù)據(jù)的最后修改時間(絕對時間)作為值,而瀏覽器將接收到返回的數(shù)據(jù)和標識存入緩存,再次請求會自動發(fā)送 If-Modified-Since 請求頭,值為之前返回的最后修改時間(標識),服務器取出 If-Modified-Since 的值與數(shù)據(jù)的上次修改時間對比,如果上次修改時間大于了 If-Modified-Since 的值,說明被修改過,則通過 Last-Modified 響應頭返回新的最后修改時間和新的數(shù)據(jù),否則未被修改,返回狀態(tài)碼 304 通知瀏覽器命中緩存。

HTTP 1.1 版本中,服務器通過 Etag 響應頭來設置緩存標識(唯一標識,像一個指紋一樣,生成規(guī)則由服務器來決定),瀏覽器接收到數(shù)據(jù)和唯一標識后存入緩存,下次請求時,通過 If-None-Match 請求頭將唯一標識帶給服務器,服務器取出唯一標識與之前的標識對比,不同,說明修改過,返回新標識和數(shù)據(jù),相同,則返回狀態(tài)碼 304 通知瀏覽器命中緩存。

HTTP 協(xié)商緩存策略流程圖如下:

HTTP緩存的作用和規(guī)則簡介

注意:使用協(xié)商緩存時 HTTP 1.0 版本還是不太靠譜,假設一個文件增加了一個字符后又刪除了,文件相當于沒更改,但是最后修改時間變了,會被當作修改處理,本應該命中緩存,服務器卻重新發(fā)送了數(shù)據(jù),因此 HTTP 1.1 中使用的 Etag 唯一標識是根據(jù)文件內容或摘要生成的,保證了只要文件內容不變,則一定會命中緩存,為了兼容低版本 HTTP 協(xié)議,開發(fā)中兩種響應頭也會同時使用,同樣 HTTP 1.1 版本的實現(xiàn)優(yōu)先級高于 HTTP 1.0

3、通過 Network 查看協(xié)商緩存

我們同樣通過 Chrome 瀏覽器的開發(fā)者工具,打開 NetWork 查看協(xié)商緩存的相關信息。

再次請求服務器的請求頭信息:

HTTP緩存的作用和規(guī)則簡介

命中協(xié)商緩存的響應頭信息:

HTTP緩存的作用和規(guī)則簡介

下面看一看通過協(xié)商緩存取出的數(shù)據(jù)在 Network 中與第一次加載的區(qū)別。

第一次請求:

HTTP緩存的作用和規(guī)則簡介

緩存后請求:

HTTP緩存的作用和規(guī)則簡介

通過兩圖的對比,我們可以發(fā)現(xiàn),協(xié)商緩存生效時的狀態(tài)碼為 304,并且報文大小和請求時間大大減少,原因是服務端在進行標識比對后只返回了 header 部分,通過狀態(tài)碼來通知瀏覽器使用緩存,不再需要將報文主體部分一起返回給瀏覽器。

4、NodeJS 服務器實現(xiàn)協(xié)商緩存

// 協(xié)商緩存
const http = require("http");
const url = require("url");
const path = require("path");
const mime = require("mime");
const fs = require("fs");0
const crytpo = require("crytpo");

const server = http.createServer((req, res) => {
 let { pathname } = url.parse(req.url, true);
 pathname = pathname !== "/" ? pathname : "/index.html";

 // 獲取讀取文件的絕對路徑
 let p = path.join(__dirname, pathname);

 // 查看路徑是否合法
 fs.stat(p, (err, statObj) => {
  // 路徑不合法則直接中斷連接
  if (err) return res.end("Not Found");

  let md5 = crypto.createHash("md5"); // 創(chuàng)建加密的轉換流
  let rs = fs.createReadStream(p); // 創(chuàng)建可讀流

  // 讀取文件內容并加密
  rs.on("data", data => md5.update(data));

  rs.on("end", () => {
   let ctime = statObj.ctime.toGMTString(); // 獲取文件最后修改時間
   let flag = md5.digest("hex"); // 獲取加密后的唯一標識

   // 獲取協(xié)商緩存的請求頭
   let ifModifiedSince = req.headers["if-modified-since"];
   let ifNoneMatch = req.headers["if-none-match"];

   if (ifModifiedSince === ctime || ifNoneMatch === flag) {
    res.statusCode = 304;
    res.end();
   } else {
    // 設置協(xié)商緩存
    res.setHeader("Last-Modified", ctime);
    res.setHeader("Etag", flag);

    // 設置文件類型并響應給瀏覽器
    res.setHeader("Content-Type", `${mime.getType(p)};charset=utf8`);
    rs.pipe(res);
   }
  });
 });
});

server.listen(3000, () => {
 console.log("server start 3000");
});

在上面的代碼中是通過可讀流讀取文件內容,并通過 crypto 模塊進行了 md5 加密后的結果作為了唯一標識,這樣就能保證只要文件內容不變,就會命中緩存,其中兼容了 HTTP 1.0HTTP 1.1 兩個版本,只要滿足一個則直接返回 304 通知瀏覽器命中緩存。

注意:其實讀取文件內容加密這種做法并不可取,假如讀取的是大文件,在讀取文件內容和進行 md5 加密這個過程會非常消耗時間,所以在開發(fā)中要針對業(yè)務的實際情況選擇可以保證服務器性能的方式生成唯一標識,比如根據(jù)文件的摘要。

總結

為了使緩存策略更加健壯、靈活,HTTP 1.0 版本 和 HTTP 1.1 版本的緩存策略會同時使用,甚至強制緩存和協(xié)商緩存也會同時使用,對于強制緩存,服務器通知瀏覽器一個緩存時間,在緩存時間內,下次請求,直接使用緩存,超出有效時間,執(zhí)行協(xié)商緩存策略,對于協(xié)商緩存,將緩存信息中的 EtagLast-Modified 通過請求頭 If-None-MatchIf-Modified-Since 發(fā)送給服務器,由服務器校驗同時設置新的強制緩存,校驗通過并返回 304 狀態(tài)碼時,瀏覽器直接使用緩存,如果協(xié)商緩存也未命中,則服務器重新設置協(xié)商緩存的標識。

“HTTP緩存的作用和規(guī)則簡介”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經查實,將立刻刪除涉嫌侵權內容。

AI