浏览器缓存最强攻略:强缓存、协商缓存、CDN、更新策略,一篇搞定

网站加载慢?重复请求浪费带宽?用户总是看到旧版本?这些问题背后,都指向同一个关键词:缓存。今天我们从HTTP头开始,彻底搞懂强缓存、协商缓存、CDN缓存、前端静态资源版本管理,以及最常见的缓存坑和解决方案。

一、缓存是什么?为什么重要?

缓存是HTTP协议中用于复用之前获取的资源的机制。合理使用缓存可以:

  • 减少网络请求,页面加载更快
  • 降低服务器压力
  • 节省用户流量

但缓存用不好,会导致用户看到过期内容,或者每次都重新下载,失去缓存意义。

二、强缓存:服务器告诉浏览器"别问了,直接用旧的"

强缓存由服务器返回的响应头中的 Cache-Control(HTTP/1.1)或 Expires(HTTP/1.0,已过时)控制。

2.1 Cache-Control 常用指令

指令 含义
max-age=3600 资源在3600秒内是"新鲜的",直接使用缓存,不请求服务器
no-cache 跳过强缓存,但可以用协商缓存(见下文)
no-store 完全不缓存,每次都重新下载
public 可以被任何中间节点(CDN、代理)缓存
private 只能被浏览器缓存,不能给中间节点(如用户个人信息)
immutable 资源永不变化(通常配合带hash的文件名使用),浏览器不必再验证

2.2 强缓存流程

ini 复制代码
浏览器请求资源 → 服务器返回资源 + Cache-Control: max-age=3600
→ 浏览器缓存该资源,3600秒内再次请求直接读缓存(200 from disk cache)
→ 3600秒后重新请求服务器

2.3 如何绕过强缓存?

  • 刷新页面(F5 / Cmd+R):浏览器会带上 Cache-Control: max-age=0,告诉服务器不要用缓存,走协商缓存。
  • 硬刷新(Ctrl+F5 / Cmd+Shift+R):浏览器带上 Cache-Control: no-cache,强制重新下载。

三、协商缓存:浏览器问服务器"资源变了吗?"

当强缓存过期,或者请求头带有 Cache-Control: no-cache 时,浏览器会发起协商缓存请求,询问服务器资源是否有更新。

3.1 Last-Modified / If-Modified-Since

服务器返回 Last-Modified(资源最后修改时间),浏览器下次请求带上 If-Modified-Since。服务器比对时间,若未修改则返回 304 Not Modified,浏览器使用缓存;若修改则返回200和新资源。

缺点

  • 时间精度为秒,如果文件在1秒内多次修改,可能无法检测到。
  • 如果文件内容没变但时间变了(如CI重新生成),也会导致重新下载。

3.2 ETag / If-None-Match(推荐)

ETag 是服务器根据文件内容生成的唯一标识(哈希值),更精确。浏览器下次请求带上 If-None-Match: "某hash"。若未变则返回304,否则返回200和新资源。

优先级:ETag 高于 Last-Modified。

3.3 协商缓存流程

makefile 复制代码
浏览器: 我有个资源,ETag是"abc",你变了没?
服务器: 没变,304,你继续用旧的
浏览器: (用缓存)

四、强缓存 vs 协商缓存对比

特性 强缓存 协商缓存
发起请求 不发(直接用缓存) 发,但服务端不返回体
状态码 200 (from disk/memory cache) 304
控制头 Cache-Control / Expires Last-Modified / ETag
适用场景 不常变的静态资源(JS/CSS/图片) 可能变化的HTML、API响应

五、最佳实践:如何配置?

5.1 静态资源(JS/CSS/图片):强缓存 + 文件名hash

nginx 复制代码
location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
    expires 1y;
    add_header Cache-Control "public, immutable";
}

注意 :文件名必须带hash(如 main.a3f2b1c.js),内容变化时hash变化,浏览器才会重新下载。这是目前最主流的前端静态资源缓存策略。

5.2 HTML文件:协商缓存或 no-cache

nginx 复制代码
location ~ \.html$ {
    add_header Cache-Control "no-cache";
}

因为HTML需要随时更新(入口文件),不能强缓存。

5.3 API响应:按需

  • 动态数据:Cache-Control: no-cache
  • 相对固定的数据(如配置):Cache-Control: max-age=60(短时缓存)

六、前端更新痛点与解决方案

问题:用户看到旧版本

常见于:

  • 部署新版本后,用户浏览器缓存的旧CSS/JS未更新,导致页面错乱。
  • 入口HTML被强缓存,用户没拿到新版本入口,自然不会请求新资源。

解决方案:

  1. HTML文件用协商缓存或短时缓存 (如 max-age=60)。
  2. 静态资源用文件名hash + 强缓存
  3. 通过构建工具(Webpack/Vite)自动生成带hash的文件名
  4. 部署时先上静态资源,后上HTML。确保HTML引用的是最新的资源hash。
  5. 可选项:在HTML中插入版本号或 query string(不推荐,因为可能被代理忽略)。

七、CDN缓存

CDN是"反向代理缓存",缓存静态资源在全球边缘节点。配置时需注意:

  • 通过 Cache-Control: public 允许CDN缓存。
  • 设置合适的 max-age,太短会增加回源请求,太长会导致更新不及时。
  • 刷新CDN缓存通常需要手动调用API或版本化URL。

八、调试缓存

Chrome DevTools:

  • Network 面板:Size 列显示 (memory cache)(disk cache) 或状态码304。
  • Disable cache 复选框:临时禁止缓存(仅限DevTools开启时)。
  • ApplicationCache Storage:查看Service Worker缓存。
  • Clear site data:清除当前网站的缓存。

常用命令:

  • 硬刷新:Cmd+Shift+R (Mac) / Ctrl+F5 (Windows)
  • 清除缓存并硬刷新:打开DevTools后右键刷新按钮选择"Empty Cache and Hard Reload"

九、常见坑点

原因 解决
上线后用户还是旧版本 HTML被强缓存 HTML用no-cache或短时缓存
CSS改了,页面样式还是旧的 CSS文件名没变,浏览器强缓存 文件名加hash
图片更新了,还是旧图 CDN缓存未刷新 版本化URL或主动刷新CDN
304请求多,还是慢 强缓存没开,每次都协商 给静态资源加max-age

十、总结

场景 推荐配置
静态资源(带hash) Cache-Control: max-age=31536000, immutable
HTML入口 Cache-Control: no-cache
API(不变数据) Cache-Control: max-age=60
API(动态) Cache-Control: no-cache
用户头像等私有资源 Cache-Control: private, max-age=3600

缓存策略没有"标准答案",需要根据业务需求权衡实时性和性能。但记住:带hash的静态资源放心强缓存,入口文件绝不强缓存

相关推荐
cyadyx1 小时前
Vite 比 Webpack 构建效率更高
前端·webpack·node.js·vite
mCell3 小时前
AI 时代 SVG 画图的潜力
前端·agent·svg
我命由我123458 小时前
CesiumJS 笔记 - 获取容器中心点、Cartesian3 clone 方法、修改 Cartesian3 对象的高度
前端·javascript·css·前端框架·html·html5·js
Hopebearer_9 小时前
页面突然只剩 DOM?一次静态资源版本错配排查
前端·部署
东风破_10 小时前
ESLint 是什么?为什么你的项目需要它?
前端·后端·代码规范
圣殿骑士-Khtangc11 小时前
Go字符串高效拼接性能对比与底层原理分析
服务器·前端·golang
ShineWinsu11 小时前
对于C++:C++11中lambda、function、bind的解析
c++·面试·笔试·开发·lambda·bind·function
码匠许师傅11 小时前
【C++ 面试真题】聊聊 C++ 的拷贝构造与拷贝赋值
java·c++·面试
BigTopOne12 小时前
【ijkplayer】 硬解码流程
前端
kyriewen12 小时前
DeepSeek Harness开源第一天我就上手了——和Claude Code的差距比想象中大
前端·ai编程·deepseek