HTTP 缓存是浏览器、代理服务器、CDN 等根据 HTTP 响应头,把资源副本保存下来,后续请求尽量复用,从而减少网络请求、加快加载、降低服务器压力。
一、两类核心缓存
| 类型 | 判断依据 | 是否发请求到服务器 | 浏览器表现 |
|---|---|---|---|
| 强缓存 | Cache-Control: max-age、Expires |
不发请求 | 200 (from memory/disk cache) |
| 协商缓存 | ETag / Last-Modified |
发请求验证 | 未变:304;变了:200 |
优先级:
Cache-Control>ExpiresETag>Last-Modified
二、常用响应头
1. 强缓存相关
http
yaml
Cache-Control: max-age=31536000, public, immutable
Expires: Wed, 21 Oct 2026 07:28:00 GMT
常见指令:
max-age=秒:资源在多少秒内可直接用本地缓存。s-maxage=秒:只对 CDN、代理等共享缓存生效。public:允许浏览器和 CDN 缓存。private:只允许浏览器缓存,不允许 CDN 缓存。no-cache:可以缓存,但每次使用前必须向服务器验证。no-store:完全不缓存。must-revalidate:过期后必须验证,不能用旧缓存。immutable:资源不会变,浏览器在有效期内不要发验证请求。stale-while-revalidate=秒:过期后先用旧缓存,同时后台更新。
注意:no-cache 不是"不缓存",no-store 才是"不缓存"。
2. 协商缓存相关
http
yaml
ETag: "abc123"
Last-Modified: Tue, 20 Oct 2026 10:00:00 GMT
下次请求会带上:
http
less
If-None-Match: "abc123"
If-Modified-Since: Tue, 20 Oct 2026 10:00:00 GMT
服务器判断:
- 没变:返回
304 Not Modified,不返回资源体。 - 变了:返回
200 OK和新资源。
三、缓存流程
- 第一次请求资源,服务器返回
200和缓存头。 - 再次请求时,先看强缓存是否还在有效期内。
- 有效:直接使用本地缓存,不发请求。
- 失效:带
If-None-Match/If-Modified-Since请求服务器。 - 服务器返回
304:继续用本地缓存,并更新缓存头。 - 服务器返回
200:用新资源覆盖缓存。 - 如果响应是
no-store,则完全不保存。 - 整个流程静态资源放在nginx里设置,一些接口如果是获取地区的接口可以放入后端设置响应头,浏览器下次自动携带
css
浏览器请求资源
↓
是否有本地缓存?
├─ 无 → 请求服务器,返回200,同时带回缓存头,存入本地
└─ 有 → 判断【强缓存是否有效】(max-age/Expires)
├─ ✅命中强缓存 → 直接读本地缓存 200(from cache),不访问后端
└─ ❌强缓存过期 → 发起请求,带上协商缓存标识(If-Modified-Since / If-None-Match)
↓
服务器对比
├─ ✅内容没变 → 返回304 Not Modified,无响应body,浏览器复用本地缓存
└─ ❌内容变更 → 返回200 + 新资源 + 新缓存头,更新本地缓存
四、常见缓存位置
- 浏览器内存缓存:memory cache,速度快,页面关闭可能消失。
- 浏览器磁盘缓存:disk cache,持久化。
- Service Worker Cache:前端可编程控制。
- CDN / 反向代理缓存:共享缓存,常配合
s-maxage。 - 代理服务器(Nginx)缓存:企业网关、运营商缓存等。
- localStorage:用于亮暗模式,用户偏好
- Cookie:
Set-Cookie: session_id=xxx; HttpOnly; Secure; SameSite=Lax; Max-Age=86400 - indexedDB:大数据,离线邮箱,笔记,新闻,视频
- Server Worker
五、Nginx缓存
一个典型的前端项目 Nginx 配置片段如下:
ruby
server {
listen 80;
server_name your-domain.com;
# 项目根目录(请替换为你的实际路径)
root /usr/share/nginx/html;
# 1. 针对带哈希值的静态资源(如 app.abc123.js)配置长期强缓存
location ~* \.[a-f0-9]{8,}\.(js|css|png|jpg|jpeg|gif|svg|webp|ico|woff|woff2)$ {
# 强缓存1年,并标记为不可变,浏览器在有效期内不会发起验证请求
add_header Cache-Control "public, max-age=31536000, immutable" always;
access_log off; # 可选:关闭日志以减少磁盘I/O
}
# 2. 针对其他固定名称的静态资源(如 logo.png)配置较短的强缓存
location ~* \.(css|js|png|jpg|jpeg|gif|svg|webp|ico|woff|woff2)$ {
# 强缓存30天,允许浏览器和CDN缓存
add_header Cache-Control "public, max-age=2592000" always;
}
# 3. 针对 HTML 入口文件(如 index.html)配置协商缓存
location ~* \.html$ {
# 允许浏览器缓存,但每次使用前必须向服务器验证
# 'private' 禁止中间代理(如CDN)缓存此响应
add_header Cache-Control "private, no-cache, must-revalidate" always;
# Nginx 默认会为此类文件提供 ETag 和 Last-Modified 以支持验证
}
# 4. SPA(单页应用)的路由回退配置
# 这确保了前端路由刷新时不会出现 404 错误
location / {
try_files $uri $uri/ /index.html;
}
}
项目打包好,通过pnpm build 生成dist目录,上传服务器
bash
/usr/share/nginx/html/ # Nginx 配置的 root 目录
├── index.html # 应用入口文件
├── assets/ # 构建工具生成的资源目录
│ ├── app.a1b2c3d4.js # 带哈希的 JS 文件
│ └── style.e5f6g7h8.css # 带哈希的 CSS 文件
└── favicon.ico
六、实践建议
-
带 hash 的静态资源:
app.8f3a2.js、style.1c9d.csshttp
arduinoCache-Control: public, max-age=31536000, immutable -
HTML 入口文件:
http
yamlCache-Control: no-cache这样每次会验证,确保引用最新资源。