設定 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-ModifiedETag。The index.html falls into this category. 您可以將這項作業分成兩個步驟。

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

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

完成靜態檔案伺服器的修改後,您可以開啟開發人員工具的「網路」面板,預覽即時應用程式,確認系統是否設定正確的標頭。

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

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

請注意 NameStatusCache-ControlETagLast-Modified 欄。

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

頁面載入後,您應該會在「Network」面板中看到類似下列的項目:

「網路」面板的資料欄。

第一列是您前往的 HTML 文件。這會透過 Cache-Control: no-cache 正確放送。該要求的 HTTP 回應狀態為 304。這表示瀏覽器知道不要立即使用快取 HTML,而是使用 Last-ModifiedETag 資訊向網路伺服器發出 HTTP 要求,確認快取中的 HTML 是否有任何更新。Last-ModifiedETagHTTP 304 回應表示沒有更新的 HTML。

接下來的兩列是 JavaScript 和 CSS 資產的版本。您應該會看到這些資源以 Cache-Control: max-age=31536000 提供,且每個資源的 HTTP 狀態都是 200。 由於使用的設定,系統不會向 Node.js 伺服器發出實際要求,點選項目會顯示額外詳細資料,包括回應來自「(磁碟快取)」。

網路回應狀態為 200。

ETag 和 Last-Modified 欄的實際值並不重要。重點是確認是否已設定這些值。

總結

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