設定 HTTP 快取行為

本程式碼研究室說明如何變更 Node.js 型網路伺服器傳回的 HTTP 快取標頭,並執行 Express 服務架構。文中也會顯示使用 Chrome 開發人員工具的網路面板,確認系統是否確實套用了預期的快取行為。

熟悉範例專案

以下是您在範例專案中會使用的主要檔案:

  • server.js 包含可提供網頁應用程式內容的 Node.js 程式碼。並會使用 Express 處理 HTTP 要求和回應。具體來說,express.static() 是用來提供公開目錄中的所有本機檔案,因此 serve-static 說明文件可派上用場。
  • public/index.html 是網頁應用程式的 HTML。與大多數 HTML 檔案一樣,這個檔案不包含任何版本資訊。
  • public/app.15261a07.jspublic/style.391484cf.css 是網頁應用程式的 JavaScript 和 CSS 素材資源。這些檔案網址的每個網址都包含雜湊,對應其內容。index.html 負責追蹤要載入的特定版本網址。

設定 HTML 的快取標頭

如要回應不含版本管理資訊的網址要求,請務必在回應訊息中加入 Cache-Control: no-cache。除此之外,建議您另外設定以下兩個回應標頭之一:Last-ModifiedETagindex.html 屬於這個類別。您可將此分為兩個步驟。

首先,Last-ModifiedETag 標頭是由 etaglastModified 設定選項控管。這兩個選項實際上在所有 HTTP 回應中都預設為 true,因此在目前的設定中,您無須選擇取得該行為。但您仍可在設定中明確指定。

接著,您必須能加入 Cache-Control: no-cache 標頭,但僅適用於 HTML 文件 (在本例中為 index.html)。如要有條件設定這個標頭,最簡單的方法是編寫自訂 setHeaders function,然後在其中檢查傳入要求是否針對 HTML 文件。

  • 按一下「Remix to Edit」,讓專案可供編輯。

server.js 中的靜態提供設定一開始如下:

app.use(express.static('public'));
  • 進行上述變更,結果看起來應該會像這樣:
app.use(express.static('public', {
  etag: true, // Just being explicit about the default.
  lastModified: true,  // Just being explicit about the default.
  setHeaders: (res, path) => {
    if (path.endsWith('.html')) {
      // All of the project's HTML files end in .html
      res.setHeader('Cache-Control', 'no-cache');
    }
  },
}));

為版本化網址設定快取標頭

如要回應含有「指紋」或版本資訊,且其內容永遠不會改變的要求,請在回應中加入 Cache-Control: max-age=31536000app.15261a07.jsstyle.391484cf.css 屬於這個類別。

以最後一個步驟中使用的 setHeaders function 為基礎,新增額外的邏輯來檢查特定要求是否屬於版本化網址,如果是的話,請新增 Cache-Control: max-age=31536000 標頭。

要做到這點,最可靠的方法是使用規則運算式,查看要求的資產是否與您知道雜湊值的特定模式相符。在這個範例專案的情況下,必須是第 0 至 9 位數的八個字元,以及小寫英文字母 a-f (即十六進位字元)。雜湊值一律會以 . 字元分隔。

符合這些一般規則的規則運算式可用 new RegExp('\\.[0-9a-f]{8}\\.') 表示。

  • 修改 setHeaders 函式,如下所示:
app.use(express.static('public', {
  etag: true, // Just being explicit about the default.
  lastModified: true,  // Just being explicit about the default.
  setHeaders: (res, path) => {
    const hashRegExp = new RegExp('\\.[0-9a-f]{8}\\.');

    if (path.endsWith('.html')) {
      // All of the project's HTML files end in .html
      res.setHeader('Cache-Control', 'no-cache');
    } else if (hashRegExp.test(path)) {
      // If the RegExp matched, then we have a versioned URL.
      res.setHeader('Cache-Control', 'max-age=31536000');
    }
  },
}));

使用開發人員工具確認新行為

修改靜態檔案伺服器後,您可以在「開發人員工具 Network」面板開啟後預覽執行中的應用程式,藉此確認設定的標頭正確無誤。

  • 如要預覽網站,請按下「查看應用程式」,然後按下「全螢幕」圖示 全螢幕

  • 自訂「網路」面板中顯示的資料欄,使其包含最相關的資訊,只要在欄標題中按一下滑鼠右鍵即可:

設定開發人員工具的網路面板。

此處應留意的資料欄為 NameStatusCache-ControlETagLast-Modified

  • 開啟開發人員工具到「Network」面板後,重新整理頁面。

頁面載入後,您應該會在「網路」面板中看到類似以下的內容:

網路面板欄。

第一列代表您要瀏覽的 HTML 文件。這會透過 Cache-Control: no-cache 正確提供。該要求的 HTTP 回應狀態為 304。這表示瀏覽器知道不會立即使用快取 HTML,而是使用 Last-ModifiedETag 資訊對網路伺服器發出 HTTP 要求,查看快取中是否有 HTML 更新。HTTP 304 回應表示 HTML 未更新。

接下來兩列代表版本化 JavaScript 和 CSS 素材資源。您應該會看到與 Cache-Control: max-age=31536000 一同提供,而每個項目的 HTTP 狀態則為 200。依據使用的設定,系統不會實際向 Node.js 伺服器發出要求,按一下項目會顯示其他詳細資料,包括回應為「(來自磁碟快取)」。

網路回應狀態為 200。

ETag 與 Last-Modified 資料欄的實際值並不重要。重要的是,您應確認設定這些參數。

總結內容

完成本程式碼研究室的步驟後,您現在熟悉如何使用 Express 在以 Node.js 為基礎的網路伺服器中設定 HTTP 回應標頭,以達到最佳的 HTTP 快取使用情形。您也可以透過 Chrome 開發人員工具中的網路面板,確認正在使用預期的快取行為。