浏览器缓存是提升网页性能的核心机制,它通过存储资源副本(如HTML、CSS、JS、图片等),在后续请求时直接复用本地资源。

缓存的价值

减少网络请求:减少重复资源传输,降低服务器负载,节省服务器带宽加速页面加载:使用缓存时,从本地磁盘/内存读取资源比网络请求快数十倍

资源缓存的位置:

位置 (按读取速度排序)特性生命周期Memory Cache内存缓存,读取速度最快会话级,关闭浏览器标签页即失效Disk Cache磁盘缓存,容量大但速度稍慢持久存储,手动或过期才清除Service Worker可编程缓存,支持离线、拦截请求完全由代码控制缓存哪些文件、如何匹配/读取缓存,且缓存是持续性的Push Cache推送缓存,以上都没命中时,才启用会话级,关闭浏览器标签页即失效

缓存流程:

浏览器内部维护了一个 缓存存储(包括Memory Cache、Disk Cache等)

// 伪代码:浏览器缓存数据库结构

const cacheStorage = {

"https://example.com/logo.png": {

responseHeaders: {

"Cache-Control": "max-age=3600",

"ETag": "deadbeef123",

"Date": "Wed, 19 Jul 2025 08:00:00 GMT"

},

body: [图片二进制数据],

expirationTime: 1721386800000 // 2025-07-19 09:00:00

},

"https://api.com/user": {

// 另一个缓存条目...

}

}

当浏览器发起一个 HTTP 请求时,会先在 缓存存储 中查找是否有匹配的 URL

若有匹配的 URL:则根据该 缓存信息 来检查强缓存

强缓存:检查Cache-contral(是否允许使用缓存?) 和Expires(缓存是否过期?),若强缓存失效,则进入协商缓存。协商缓存:携带 缓存验证字段 向服务器发送请求,验证缓存资源是否最新

若没有匹配的 URL:则向服务器发送此请求,并根据 响应头 来存储 缓存信息

关键缓存策略

强缓存

注意:此过程不产生任何网络请求

协商缓存

读取 缓存信息:

若存在 Etag --> 准备 If-None-Match头若存在 Last-Modified --> 准备 If-Modified-Since头

发送带 验证头 的轻量请求

GET /data.json HTTP/1.1

Host: api.example.com

If-None-Match: "deadbeef123"

If-Modified-Since: Wed, 19 Jul 2025 08:00:00 GMT

服务器验证逻辑:

资源未变 --> 返回 304 Not Modified(空 body)资源已变 --> 返回 200 OK + 新数据

浏览器处理响应:

收到 304 --> 从缓存读取数据收到 200 --> 使用新数据并更新缓存

缓存相关字段

服务器响应头

字段说明示例值Cache-Control最重要的缓存控制头(HTTP/1.1)max-age=3600, publicExpires资源过期绝对时间(HTTP/1.0,已被Cache-Control取代)Expires: Wed, 21 Oct 2025 07:28:00 GMT缺点:判断是否过期时是使用本地时间,而本地时间可以修改ETag资源唯一标识符(通常是内容哈希值)ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4"Last-Modified资源最后修改时间Last-Modified: Mon, 01 Jul 2024 12:00:00 GMTVary指定哪些请求头影响缓存版本Vary: User-AgentAge资源在代理缓存中已存储的时间(秒)Age: 600PragmaHTTP/1.0遗留字段(等同于Cache-Control: no-cache)Pragma: no-cache

浏览器请求头

字段说明触发条件If-None-Match携带缓存的ETag值进行验证响应头中有ETagIf-Modified-Since携带缓存的最后修改时间进行验证响应头中有Last-ModifiedCache-Control客户端可覆盖缓存行为用户强制刷新时If-Match用于更新操作时的条件请求非GET请求

核心字段解析

Cache-Control:最强大的缓存控制字段,支持以下多种指令组合

指令作用使用场景max-age=<秒>资源有效期(相对时间)max-age=3600(1小时有效)s-maxage=<秒>覆盖max-age但仅对共享缓存有效(如CDN)s-maxage=86400(CDN缓存1天)public允许任何缓存(浏览器、CDN等)公开资源:Cache-Control: public, max-age=3600private仅允许用户浏览器缓存用户私有数据:Cache-Control: private, max-age=600no-cache跳过强缓存,强制向服务器验证重要数据:Cache-Control: no-cacheno-store完全禁用缓存(不存储任何版本)敏感数据:Cache-Control: no-storemust-revalidate缓存过期后必须向服务器验证Cache-Control: max-age=3600, must-revalidate当资源过期且浏览器无法链接服务器时:普通缓存可能展示过期数据(浏览器宽容策略),但设置了must-revalidate会直接报错504 Gateway Timeout(拒绝使用过期缓存)immutable资源永不变,用户刷新也不验证哈希版本资源:Cache-Control: max-age=31536000, immutablestale-while-revalidate允许使用过期缓存同时后台更新Cache-Control: max-age=3600, stale-while-revalidate=86400stale-if-error服务器错误时使用过期缓存的时间Cache-Control: max-age=3600, stale-if-error=86400

资源的最佳缓存策略

资源类型配置策略理由频繁变动的资源Cache-Contral:no-cache直接进入协商缓存,配合 Etag 或 Last-Modified 来验证资源是否有效。 这样做虽然不能节省请求数量,但能显著减少响应数据大小不常变化的资源Cache-Control:man-age=31536000设置很大的有效期,进入强缓存。 若资源更新了,需要更改资源名称中的 hash / 版本号 等动态字符,达到更改 URL 的目的。# 以一个 nginx 配置为例

location /share {

if ($request_filename ~* ^.*[.](html|htm)$) {

#html文件不缓存

expires 0;

add_header Cache-Control "no-store";

}

if ($request_filename ~* ^.*[.](js|css|json)$) {

#不带hash的静态资源,设置协商缓存

add_header Cache-Control "no-cache";

}

if ($request_filename ~* .*.(chunk).(css|js)$) {

#匹配带hash的js css强缓存1个月

add_header Cache-Control "public, max-age=2592000";

}

if ($request_filename ~* ^.*[.](png|jpg|svg|ico)$) {

#匹配静态png jpg 资源强缓存1个月

add_header Cache-Control "public, max-age=2592000";

}

if ($request_filename ~* ^.*[.]migrate.dll.js$){

#匹配migarte的js文件 协商缓存

add_header Cache-Control "no-cache";

}

if ($request_filename ~* ^.*[.]migrate.css$){

#匹配migarte的css文件 协商缓存

add_header Cache-Control "no-cache";

}

alias "/opt/web/build";

index index.html;

try_files $uri $uri/ /share/index.html;

}

用户操作对缓存的影响

用户操作缓存行为技术细节打开网页,地址栏输入地址使用 Disk Cache ,若有则使用缓存资源,若没有则发送请求前进/后退优先使用页面快照(bfcache),不重新请求资源。整个页面从内存恢复,资源不重新加载(PageShow 事件可监听)。普通刷新(F5)跳过强缓存,触发协商缓存验证。优先使用 Memory Cache,其次使用 Disk Cache请求头带有缓存校验字段(If-Modified-Since等),服务器决定返回 304 或 200。强制刷新(Ctrl+F5)不使用缓存请求头带有Cache-Control: no-cache (为了兼容,还带了 Pragma: no-cache),服务器返回 200和最新资源。