配置 HTTP 缓存行为

本代码实验室向您展示如何更改由基于 Node.js 的 Web 服务器返回的 HTTP 缓存标头,该服务器运行 Express 服务框架。它还将展示如何使用 Chrome DevTools 中的“网络”面板确认您期望的缓存行为是否实际应用。

熟悉示例项目

以下是您将在示例项目中使用的主要文件

  • server.js 包含 Node.js 代码,用于提供 Web 应用的内容。它使用 Express 来处理 HTTP 请求和响应。特别是,express.static() 用于提供 public 目录中所有本地文件,因此 serve-static 文档 将会派上用场。
  • public/index.html 是 Web 应用的 HTML。与大多数 HTML 文件一样,它不包含任何作为其 URL 一部分的版本控制信息。
  • public/app.15261a07.jspublic/style.391484cf.css 是 Web 应用的 JavaScript 和 CSS 资源。这些文件的 URL 中都包含哈希值,与它们的内容相对应。index.html 负责跟踪要加载的特定版本化 URL。

为我们的 HTML 配置缓存标头

当响应不包含版本控制信息的 URL 请求时,请确保将 Cache-Control: no-cache 添加到您的响应消息中。 除此之外,建议设置两个附加响应标头中的一个:Last-ModifiedETagindex.html 属于此类。您可以将其分解为两个步骤。

首先,Last-ModifiedETag 标头由 etaglastModified 配置选项控制。实际上,这两个选项对于所有 HTTP 响应都默认为 true,因此在当前设置中,您不必选择加入以获得该行为。但是,您仍然可以在配置中明确指定。

其次,您需要能够添加 Cache-Control: no-cache 标头,但仅用于 HTML 文档(在本例中为 index.html)。有条件地设置此标头的最简单方法是编写自定义 setHeaders 函数,并在其中检查传入的请求是否针对 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');
    }
  },
}));

为版本化 URL 配置缓存标头

当响应包含“指纹”或版本控制信息的 URL 请求,并且其内容永远不会更改时,请将 Cache-Control: max-age=31536000 添加到您的响应中。app.15261a07.jsstyle.391484cf.css 属于此类。

在最后一步中使用的 setHeaders 函数 的基础上,您可以添加额外的逻辑来检查给定请求是否针对版本化 URL,如果是,则添加 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 确认新行为

完成对静态文件服务器的修改后,您可以通过预览打开 DevTools “网络”面板的实时应用来检查是否已设置正确的标头。

  • 要预览该网站,请按 View App(查看应用)。然后按 Fullscreen(全屏) fullscreen

  • 通过在列标题中单击鼠标右键,自定义“网络”面板中显示的列,以包含最相关的信息

Configuring DevTools' Network panel.

在此处,需要注意的列是 NameStatusCache-ControlETagLast-Modified

  • 打开 DevTools 并转到“网络”面板后,刷新页面。

页面加载后,您应该在“网络”面板中看到如下所示的条目

Network panel columns.

第一行是您导航到的 HTML 文档。它已正确地使用 Cache-Control: no-cache 提供。该请求的 HTTP 响应状态为 304。这意味着浏览器知道不要立即使用缓存的 HTML,而是向 Web 服务器发出 HTTP 请求,使用 Last-ModifiedETag 信息来查看它已在其缓存中的 HTML 是否有任何更新。HTTP 304 响应表明没有更新的 HTML。

接下来的两行是版本化的 JavaScript 和 CSS 资源。您应该看到它们使用 Cache-Control: max-age=31536000 提供,并且每个的 HTTP 状态均为 200。由于使用的配置,实际上没有向 Node.js 服务器发出任何请求,并且点击条目将向您显示更多详细信息,包括响应来自“(磁盘缓存)”。

A network response status of 200.

ETag 和 Last-Modified 列的实际值并不重要。重要的是确认它们已被设置。

总结

完成本代码实验室中的步骤后,您现在熟悉如何在基于 Node.js 的 Web 服务器中使用 Express 配置 HTTP 响应标头,以实现 HTTP 缓存的最佳使用。您还掌握了通过 Chrome DevTools 中的“网络”面板确认是否正在使用预期缓存行为的步骤。