前言:为什么缓存如此重要?
在 Web 开发中,缓存是提升性能、减少服务器压力、加快页面加载速度的核心手段之一。浏览器缓存机制分为两大类:
强缓存(本地缓存)
弱缓存(协商缓存)
很多人只知道“缓存”这个词,却不知道它们背后的机制、HTTP 响应头的作用、以及如何在实际项目中配置。本文将从零开始,带你彻底搞懂这两类缓存。
一、缓存的基本流程图(浏览器视角)
%% 浏览器视角的缓存总览
flowchart TD
A[用户访问页面] --> B{本地有缓存?}
B -->|是| C{强缓存生效?}
B -->|否| D[直接请求服务器]
C -->|是| E[200 from cache<br>直接使用]
C -->|否| F[发起协商缓存请求]
F --> G{服务器验证}
G -->|304 无更新| H[沿用旧缓存]
G -->|200 有更新| I[下载新资源并缓存]
一、为什么缓存是性能优化的“最后一公里”
减少重复网络请求,降低 RTT(Round-Trip Time)。
减轻源站压力,节省 CDN 流量费用。
提升首屏与交互响应速度,改善 Core Web Vitals 指标。
二、强缓存:浏览器“独断专行”
2.1 定义
在缓存有效期内,浏览器不会发任何 HTTP 请求,直接读取本地副本。
2.2 控制字段
字段
协议版本
示例值
优先级
Cache-Control
HTTP/1.1
max-age=3600
高
Expires
HTTP/1.0
Wed, 21 Oct 2025 07:28:00 GMT
低(仅作兼容)
生产环境请只使用 Cache-Control,放弃 Expires。
2.3 Cache-Control 常用指令
max-age=<秒>:相对时间,最大有效时长。
s-maxage=<秒>:覆盖 max-age,仅对共享缓存(CDN)生效。
public:允许任意中间节点缓存。
private:只允许浏览器缓存。
no-cache:强制走协商缓存,每次必须验证。
no-store:禁止任何缓存(最严格)。
immutable:声明资源永久不变,Firefox/Chromium 均支持。
2.4 强缓存生效表现
http复制代码
HTTP/1.1 200 OK
Content-Type: image/webp
Cache-Control: public, max-age=86400
强缓存失效后,浏览器携带凭证询问服务器资源是否更新;若未变,服务器返回 304 Not Modified,浏览器继续用本地副本。
3.2 两组验证字段
%% 协商缓存交互
sequenceDiagram
participant B as Browser
participant S as Server
B->>S: GET /style.css<br>If-None-Match: "5d8c72a5"
S->>S: 计算最新 ETag
alt 资源无变化
S-->>B: 304 Not Modified
else 资源已变化
S-->>B: 200 OK + 新资源 + 新ETag
end
响应头
请求头
说明
ETag
If-None-Match
内容指纹(推荐)
Last-Modified
If-Modified-Since
最后修改时间(秒级精度)
ETag 优先级高于 Last-Modified;两者可同时存在。
3.3 协商缓存生效表现
首次请求:
http复制代码
HTTP/1.1 200 OK
ETag: "5d8c72a5"
Content-Type: text/css
再次请求:
http复制代码
GET /style.css
If-None-Match: "5d8c72a5"
服务器返回:
http复制代码
HTTP/1.1 304 Not Modified
DevTools 看到:体积 0 B,状态 304。
四、缓存决策树(一张图记住)
%% 缓存决策树
flowchart TD
Start([浏览器请求资源]) --> A{Cache-Control<br>允许缓存?}
A -->|no-store| B[直接请求<br>不缓存]
A -->|public/private| C{是否过期?<br>max-age/Expires}
C -->|未过期| D[200 from cache<br>强缓存]
C -->|已过期| E{ETag/Last-Modified<br>是否存在?}
E -->|是| F[带凭证请求<br>协商缓存]
E -->|否| G[重新下载<br>200 OK]
F --> H{服务器验证}
H -->|304| I[沿用旧资源]
H -->|200| J[下载并更新缓存]