说在前面
HTTP缓存 是浏览器或代理服务器对之前请求过的资源进行存储,当再次请求相同资源时,可以直接从本地缓存中获取,避免重复向服务器发起请求的机制,可显著减少网络传输量、降低服务器负载、提升用户体验。
核心流程
首次请求
客户端向服务器请求资源,服务器返回资源及缓存控制头(如 Cache-Control
、Expires
),浏览器将资源存储到本地缓存。
后续请求
客户端再次请求相同资源时,优先检查本地缓存:
- 若缓存有效:直接返回缓存资源(状态码
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
),服务器根据标识判断是否返回新资源。
ETag
/If-None-Match
(精确匹配)
- 服务器通过
ETag
返回资源的唯一标识(如文件哈希值)。 - 浏览器下次请求时携带
If-None-Match: <ETag值>
,服务器对比标识:- 一致:返回
304 Not Modified
。 - 不一致:返回新资源及新
ETag
。
- 一致:返回
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,现在是一名前端工程师,有空会刷刷算法题,平时喜欢打羽毛球 🏸 ,平时也喜欢写些东西,既为自己记录 📋,也希望可以对大家有那么一丢丢的帮助,写的不好望多多谅解 🙇,写错的地方望指出,定会认真改进 😊,偶尔也会在自己的公众号『
前端也能这么有趣
』发一些比较有趣的文章,有兴趣的也可以关注下。在此谢谢大家的支持,我们下文再见 🙌。