浏览器缓存策略全解析:Cache-Control、ETag 与 CDN 优化

性能优化

HTTP 缓存的两个层次

浏览器请求资源
     ↓
① 强缓存(不需要请求服务器)
   Cache-Control: max-age=31536000
     ↓ 过期
② 协商缓存(请求服务器确认是否变更)
   ETag / Last-Modified → 304 Not Modified
     ↓ 资源已变更
③ 从服务器获取新资源 → 200 OK

Cache-Control 指令详解

指令 含义 示例场景
max-age=N N 秒内直接使用缓存 JS/CSS (1年)
s-maxage=N CDN 缓存 N 秒 HTML (1天)
no-cache 每次验证 ETag API 响应
no-store 禁止任何缓存 敏感数据
immutable 内容永不改变 hash 文件名资源
stale-while-revalidate=N 过期后 N 秒内仍可用,后台更新 i18n JSON

工具库的缓存配置

# _next/static/chunks/app-abc123.js
Cache-Control: public, max-age=31536000, immutable

# /zh-CN/pdf/merge/index.html
Cache-Control: public, max-age=3600, s-maxage=86400

# /i18n/toolClients/zh-CN.json
Cache-Control: public, max-age=86400, stale-while-revalidate=604800

ETag 协商缓存

# 首次请求
GET /api/config HTTP/1.1
→ 200 OK
   ETag: "abc123"
   Cache-Control: no-cache

# 再次请求
GET /api/config HTTP/1.1
   If-None-Match: "abc123"
→ 304 Not Modified (空 body,节省带宽)

ETag 基于内容 hash 生成。内容不变则返回 304,浏览器使用本地缓存。


CDN 缓存架构

工具库部署在阿里云 OSS + CDN:

用户请求 https://www.toolsku.com/zh-CN/
     ↓
CDN 边缘节点(北京/上海/广州)
     ↓ 缓存命中 → 直接返回(TTFB ~20ms)
     ↓ 缓存未命中
OSS 源站(北京)
     ↓ 返回资源 + 写入 CDN 缓存
CDN → 用户

缓存 Key 设计

CDN 缓存 Key 通常为 URL + Query String。注意:

  • ?v=123?v=456 是不同缓存条目
  • Accept-Language 的请求可能产生不同缓存(Vary 头)
  • 工具库使用 URL 路径区分语言(/zh-CN//en/),避免 Vary 问题

常见缓存问题

1. 更新了 JS 但用户看到旧版

原因:旧 JS 被强缓存,新 HTML 引用了新 JS 文件名但旧 JS 仍在缓存中。

解决:文件名含 content hash(Next.js 默认 _next/static/chunks/app-[hash].js),内容变化则 hash 变化,自然失效。

2. HTML 缓存导致内容不更新

解决:HTML 使用较短 max-age + s-maxage,或通过 CDN 刷新 API 主动 purge。

3. Service Worker 缓存与 HTTP 缓存冲突

Service Worker 的 fetch 事件可以拦截所有请求,优先级高于 HTTP 缓存。更新 SW 时需要递增 cache version 并清理旧缓存。


缓存调试工具

  1. Chrome DevTools → Network:查看 Size 列((disk cache) / (memory cache) / 实际大小)
  2. Response Headers:检查 Cache-Control、ETag、Age 头
  3. 工具库 HTTP 状态码速查:理解 200/304/404 等状态码含义

工具库的缓存优化成果

我们上线这套缓存策略后,用 PageSpeed Insights 和 WebPageTest 做了对比测试:

指标 优化前(无CDN) 优化后(CDN+缓存策略) 改善
TTFB(北京) ~150ms ~20ms 87% ↓
TTFB(广州) ~280ms ~25ms 91% ↓
TTFB(海外) ~800ms+ ~80ms 90% ↓
LCP 3.2s 1.8s 44% ↓
重复访问加载 ~800ms ~120ms 85% ↓
CDN 命中率 - 94.7%

实际数据来自工具库 2026年5月的监控面板。切换 CDN + 调优缓存策略后,海外用户访问速度提升了 10 倍以上。

阿里云 CDN 的具体配置

# OSS 静态资源的 CDN 缓存规则
/_next/static/*          max-age=31536000, immutable
/i18n/*                  max-age=86400, stale-while-revalidate=604800
/*.html                  max-age=3600, s-maxage=86400
/*.xml                   max-age=3600

这些配置看起来简单,但背后是根据工具库的更新频率(静态站点,每天可能部署一次)精确调校的结果。


总结

合理的缓存策略是 Web 性能的核心。强缓存 + 协商缓存 + CDN 边缘节点的三层架构,让工具库实现了 TTFB ~20-50ms 的极致首屏速度。理解 Cache-Control 指令和 ETag 机制,是前端性能优化的基本功。

📝 如果你也在用阿里云 OSS 做静态站点,强烈建议开启 CDN 并配置好缓存规则。配置成本几乎为零,但对用户体验和 SEO 排名的提升是实实在在的。


CDN 缓存刷新策略

发布新版本时需要刷新 CDN 缓存。工具库采用的渐进式刷新方案:

// 部署脚本中的 CDN 刷新逻辑
async function purgeCdnAfterDeploy() {
  // 1. 立即刷新 HTML(用户马上看到新内容)
  await cdnRefresh([`/zh-CN/`, `/en/`, `/ja/`, `/zh-TW/`]);

  // 2. 延迟刷新 JSON/i18n(避免缓存击穿)
  sleep(30000); // 30秒窗口
  await cdnRefresh([`/i18n/**`]);

  // 3. 不刷新静态资源(hash 文件名自动失效)
  // _next/static/chunks/app-[new-hash].js  ← 新 hash,自动获取
  // _next/static/chunks/app-[old-hash].js  ← 旧 hash,自然过期后 CDN 淘汰
}

不要全量 purge:一次性刷新所有资源会造成 CDN 回源压力过大。工具库的增量刷新策略让缓存命中率始终维持在 94% 以上。


浏览器缓存分区(Cache Partitioning)

Chrome 86+ 引入了缓存分区机制。同一个 URL 在不同站点(top-level site)下的缓存是隔离的:

加载位置 缓存 Key 说明
toolsku.com 直接加载 (toolsku.com, toolsku.com, lib.js) 主站直接使用
other-site.com<script src="toolsku.com/lib.js"> (other-site.com, toolsku.com, lib.js) 隔离副本

影响:CDN 共享库(如 jQuery CDN)的优势被削弱,因为不同站点间的缓存不再共享。但对工具库这种自托管资源的场景没有负面影响。


前端缓存策略速查表

资源类型 Cache-Control 原因
带 hash 的 JS/CSS/WASM max-age=31536000, immutable 内容变化 → 文件名变化 → 自然失效
HTML no-cache, max-age=0 始终协商验证,确保用户看到最新版本
i18n JSON max-age=86400, stale-while-revalidate=604800 一天内无请求,失效后仍可用旧数据等待后台更新
字体 max-age=31536000, immutable 字体很少变化
图片/Logo max-age=86400 可能更新但也需要缓存
API 响应 no-storeno-cache(依敏感度) 实时的数据不应缓存
Service Worker 脚本 max-age=86400 浏览器自动检查更新(24h 内强制 fetch)

本站提供浏览器本地工具,免注册即可试用 →

#HTTP缓存#CDN#Cache-Control#ETag#性能优化