設定 HTTP 快取行為

本程式碼研究室會說明如何變更由以 Node.js 為基礎的網路伺服器傳回的 HTTP 快取標頭,該伺服器執行 Express 服務架構。這篇文章也會說明如何使用 Chrome 開發人員工具中的「Network」面板,確認您預期的快取行為是否確實套用。

熟悉範例專案

以下是您在範例專案中會用到的關鍵檔案:

  • 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');
    }
  },
}));

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

對靜態檔案伺服器進行修改後,您可以透過 DevTools「Network」面板預覽執行中的應用程式,確認所設的標頭正確無誤。

  • 如要預覽網站,請按下「View App」。然後按下「Fullscreen」圖示 全螢幕

  • 自訂「網路」面板中顯示的資料欄,以納入最相關的資訊,方法是在資料欄標頭中按一下滑鼠右鍵:

設定 DevTools 的「Network」面板。

這裡要留意的資料欄是 NameStatusCache-ControlETagLast-Modified

  • 開啟開發人員工具至「網路」面板,然後重新整理頁面。

頁面載入後,您應該會在「網路」面板中看到如下所示的項目:

網路面板的資料欄。

第一列是您前往的 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 伺服器提出實際要求,點選項目後會顯示其他詳細資料,包括回應來自「(from disk cache)」的訊息。

網路回應狀態為 200。

ETag 和上次修改時間欄的實際值並不重要。重要的是確認這些值是否已設定。

總結

完成本程式碼研究室的步驟後,您現在已熟悉如何使用 Express 在以 Node.js 為基礎的網路伺服器中設定 HTTP 回應標頭,以便充分運用 HTTP 快取。您也可以透過 Chrome 開發人員工具中的「Network」面板,確認是否使用預期的快取行為。