前端面试常问的HTTP缓存你都搞明白了吗?

164 阅读5分钟

说在前面

HTTP缓存 是浏览器或代理服务器对之前请求过的资源进行存储,当再次请求相同资源时,可以直接从本地缓存中获取,避免重复向服务器发起请求的机制,可显著减少网络传输量、降低服务器负载、提升用户体验。

核心流程

首次请求

客户端向服务器请求资源,服务器返回资源及缓存控制头(如 Cache-ControlExpires),浏览器将资源存储到本地缓存。

后续请求

客户端再次请求相同资源时,优先检查本地缓存:

  • 若缓存有效:直接返回缓存资源(状态码 200 OK,标注 from cache)。
  • 若缓存过期:向服务器发送验证请求(携带 If-None-Match/If-Modified-Since),服务器判断资源是否更新:
    • 未更新:返回 304 Not Modified,浏览器使用本地缓存。
    • 已更新:返回新资源及新缓存规则。

缓存策略

强制缓存

浏览器根据响应头中的 Cache-Control 判断缓存是否过期,无需向服务器发送请求。

Cache-Control(HTTP/1.1 标准字段)

  • public:允许浏览器和代理服务器缓存(如 CDN)。
  • private:仅允许浏览器缓存(默认值)。
  • max-age=秒数:缓存有效期(如 max-age=3600 表示 1 小时内有效)。
  • no-cache并非禁止缓存,而是需要先验证(与协商缓存配合使用)。
  • no-store禁止缓存,每次请求必须从服务器获取资源(用于敏感数据)。

可以通过max-age来设置有效时间,我们来写个例子看看就知道了

服务端

这里我们用node简单起一个服务就好,在public目录中简单准备一个css文件

const express = require("express");
const app = express();
const path = require("path");

app.use(
  "/public",
  express.static(path.join(__dirname, "public"), {
    etag: false,
    lastModified: false,
    setHeaders: (res, path) => {
      //打印接收到请求的时间
      console.log("接收到请求的时间:", new Date());
      res.setHeader("Cache-Control", "max-age=86400");
    },
  })
);

app.listen(3000, () => {
  console.log("Server running on http://localhost:3000");
});

启动服务

css文件

css中就简单设置了一个样式

h1 {
  color: red;
}

html

html 中通过服务端请求 css 文件

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <link rel="stylesheet" href="http://localhost:3000/public/style.css" />
  </head>
  <body>
    <h1>前端也能这么有趣</h1>
  </body>
</html>

首次请求

通过上图可以看到第一次的资源是通过请求服务器拿到的,看看服务器接收到请求的时间

后续请求

缓存有效

在上图我们可以看到第二次请求css文件的时候是直接使用本地磁盘缓存的文件,服务端并没有接收到第二次请求

这时候我们修改css文件内容的话,页面也不会更新

强制刷新(ctrl+f5)才可以重新请求服务端资源:

缓存失效

如果缓存过了max-age中我们设置的时间,那缓存就会失效,这时候会重新请求服务端资源,并更新缓存,现在我们将缓存过期时间设置短一点试试

res.setHeader("Cache-Control", "max-age=10");

设置成10s,然后重新启动一下服务

从上面图片可以看到10s内的请求是取的缓存数据,超过10s后就会重新请求服务器资源并更新缓存数据。

协商缓存

浏览器发送请求时携带缓存标识(ETag/Last-Modified),服务器根据标识判断是否返回新资源。

  1. ETag/If-None-Match(精确匹配)
  • 服务器通过 ETag 返回资源的唯一标识(如文件哈希值)。
  • 浏览器下次请求时携带 If-None-Match: <ETag值>,服务器对比标识:
    • 一致:返回 304 Not Modified
    • 不一致:返回新资源及新 ETag
  1. Last-Modified/If-Modified-Since(时间匹配)
  • 服务器通过 Last-Modified 返回资源最后修改时间(如 Last-Modified: Thu, 22 May 2025 12:00:00 GMT)。
  • 浏览器下次请求时携带 If-Modified-Since: <时间值>,服务器对比时间:
    • 未修改:返回 304 Not Modified
    • 已修改:返回新资源及新 Last-Modified

服务端

const express = require("express");
const app = express();
const path = require("path");

app.use(
  "/public",
  express.static(path.join(__dirname, "public"), {
    etag: true,
    lastModified: true,
    setHeaders: (res, path) => {
      //打印接收到请求的时间
      console.log("接收到请求的时间:", new Date());
    },
  })
);

app.listen(3000, () => {
  console.log("Server running on http://localhost:3000");
});

首次请求

再次请求

缓存有效

不修改css文件内容再次请求文件时,可以看到请求的状态码是304

缓存失效

我们修改一下css文件在重新打开网页试试,这时候请求到的是最新的css文件

公众号

关注公众号『 前端也能这么有趣 』,获取更多有趣内容。

发送 加群 还可以加入群聊,一起来学习(摸鱼)吧~

说在后面

🎉 这里是 JYeontu,现在是一名前端工程师,有空会刷刷算法题,平时喜欢打羽毛球 🏸 ,平时也喜欢写些东西,既为自己记录 📋,也希望可以对大家有那么一丢丢的帮助,写的不好望多多谅解 🙇,写错的地方望指出,定会认真改进 😊,偶尔也会在自己的公众号『前端也能这么有趣』发一些比较有趣的文章,有兴趣的也可以关注下。在此谢谢大家的支持,我们下文再见 🙌。