Web缓存策略有哪些?

Web 缓存策略学习笔记

摘要 :浏览器缓存是前端性能优化的核心手段之一。它通过 HTTP 响应头控制资源是否使用本地缓存,分为强缓存 (直接用,不请求)、协商缓存 (问一下再用)和策略缓存(按场景灵活选择)三大类。理解它们的优先级和触发条件,是掌握 HTTP 缓存的关键。

一、整体流程

浏览器请求一个资源时,缓存判断的完整链路:

sql 复制代码
发起请求
  │
  ▼
┌─────────────┐    命中(未过期)
│  1. 强缓存   │ ──→ 直接使用本地缓存 ✅
│  Expires     │      (状态码 200 from cache)
│  Cache-Control│
└──────┬──────┘
       未命中 / 已过期
       ▼
┌─────────────┐    资源没变
│  2. 协商缓存   │ ──→ 返回 304,继续用旧缓存 ✅
│  Last-Modified│
│  ETag        │
└──────┬──────┘
       资源已变
       ▼
   返回新资源 200 + 更新缓存

二、强缓存

核心思想:不向服务器发请求,直接从本地读取。最快,但可能拿到过期资源。

两个关键响应头

头部 示例 说明
Expires Expires: Wed, 21 Oct 2026 07:28:00 GMT 绝对时间,服务器告诉浏览器"这个时间之前别来问我"。缺点:依赖客户端时间,改了系统时间就失效
Cache-Control Cache-Control: max-age=3600 相对秒数 ,距离现在多少秒内有效。优先级高于 Expires,推荐使用

Cache-Control 常用值

http 复制代码
Cache-Control: max-age=3600          /* 缓存 1 小时 */
Cache-Control: no-cache              /* 跳过强缓存,走协商缓存 */
Cache-Control: no-store              /* 完全不缓存 */
Cache-control: private               /* 只有浏览器可以缓存,代理/CDN 不行 */
Cache-Control: public                /* 浏览器和代理/CDN 都可以缓存 */
Cache-Control: immutable             /* 资源永不改变(如带 hash 的静态文件)*/

优先级

Cache-Control > Expires

当两者同时存在时,以 Cache-Control 为准。


三、协商缓存

核心思想:强缓存过期后,先问服务器"资源变了没",没变就继续用旧的(返回 304),变了才下载新的。

两对验证字段

类型 请求头(浏览器问) 响应头(服务器答) 原理
Last-Modified If-Modified-Since Last-Modified 对比文件的最后修改时间
ETag If-None-Match ETag 对比文件的唯一标识(哈希值)

完整交互过程

http 复制代码
/* 第一次请求(无缓存) */
GET /style.css HTTP/1.1

HTTP/1.1 200 OK
Last-Modified: Mon, 20 Jul 2026 08:00:00 GMT
ETag: "abc123"
Cache-Control: max-age=3600

/* 第二次请求(强缓存已过期,进入协商) */
GET /style.css HTTP/1.1
If-Modified-Since: Mon, 20 Jul 2026 08:00:00 GMT
If-None-Match: "abc123"

/* 服务器判断:资源没变 → 304 */
HTTP/1.1 304 Not Modified
(空 body,节省带宽)

/* 服务器判断:资源变了 → 200 + 新内容 */
HTTP/1.1 200 OK
Last-Modified: Tue, 21 Jul 2026 10:00:00 GMT
ETag: "def456"

Last-Modified vs ETag

维度 Last-Modified ETag
精度 秒级,1 秒内修改检测不到 精确到文件内容 hash
局限性 文件改了但内容不变也会重新下载;不同服务器时间不一致 无此问题
优先级 较低 较高(服务器同时返回两者时,优先用 ETag)

四、策略缓存(Service Worker / Cache API)

核心思想 :前两种缓存都由浏览器自动管理,而策略缓存通过 Service Worker 拦截网络请求,由开发者手动决定每个请求怎么处理------读缓存、走网络、还是两者结合。

Service Worker 工作原理

java 复制代码
浏览器发起请求
     │
     ▼
 Service Worker (拦截)
     │
     ├── 命中自定义缓存 → 直接返回(离线可用)
     ├── 未命中 → 发起网络请求
     │       │
     │       ├── 成功 → 返回结果 + 存入缓存(下次可直接用)
     │       └── 失败 → 返回缓存的旧版本(降级兜底)
     └── 完全不经过 SW → 正常网络请求

典型策略模式

js 复制代码
// 注册 Service Worker
if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/sw.js');
}

// sw.js 中常见的缓存策略
const CACHE_NAME = 'v1';

// 策略 1:Cache First(缓存优先)------ 静态资源用这个
// 先查缓存,有就直接返回,没有才走网络并缓存
self.addEventListener('fetch', event => {
  event.respondWith(
    caches.open(CACHE_NAME).then(cache =>
      cache.match(event.request).then(response => {
        return response || fetch(event.request).then(netResponse => {
          cache.put(event.request, netResponse.clone());
          return netResponse;
        });
      })
    )
  );
});

// 策略 2:Network First(网络优先)------ API 数据用这个
// 先走网络,失败时回退到缓存(保证数据新鲜度)
event.respondWith(
  fetch(event.request).catch(() => caches.match(event.request))
);

// 策略 3:Stale While Revalidate(过期但先返回旧版,后台更新)
// 先返回缓存,同时在后台发请求更新缓存
event.respondWith(
  caches.open(CACHE_NAME).then(cache =>
    cache.match(event.request).then(cached => {
      const fetched = fetch(event.request).then(response => {
        cache.put(event.request, response.clone());
        return response;
      });
      return cached || fetched;
    })
  )
);

适用场景

场景 推荐策略 说明
HTML 入口文件 Network First 保证拿到最新页面
JS/CSS/图片等静态资源 Cache First 或 Stale While Revalidate 变更频率低,优先速度
API 接口数据 Network First 数据需要实时性
离线应用 Cache First + 预缓存 断网也能用

五、三种缓存对比总结

维度 强缓存 协商缓存 策略缓存 (SW)
是否发请求 不发 (带验证头) 可控制
状态码 200 from cache 304 Not Modified 由开发者决定
控制方 浏览器自动 浏览器自动 开发者手动
核心字段 Expires / Cache-Control Last-Modified / ETag Cache API
离线支持 有(未过期时) 完全支持
灵活性 最高

实际项目中的最佳实践

yaml 复制代码
HTML 文件:
  Cache-Control: no-cache          (每次都协商,确保拿最新入口)

JS/CSS/图片(带 hash):
  Cache-Control: max-age=31536000, immutable   (永久缓存,hash 变了 URL 就变了)

JS/CSS/图片(不带 hash):
  Cache-Control: max-age=86400      (缓存 1 天,过期后协商)

API 接口:
  Cache-Control: no-cache           (不缓存,或用 SW 做 Network First)

六、快速记忆口诀

  • 强缓存 :时间没过直接用,max-ageExpires
  • 协商缓存 :过期了问服务器,ETagLast-Modified
  • 策略缓存:Service Worker 拦截请求,想存就存、想取就取
相关推荐
光影少年8 天前
RN 原生动画 Animated 用法、动画性能优化
react native·react.js·掘金·金石计划
光影少年11 天前
RN适配方案:屏幕适配、分辨率适配、刘海屏/全面屏适配
react native·react.js·掘金·金石计划
光影少年11 天前
RN中的StyleSheet.create 好处、内联样式弊端
react native·react.js·掘金·金石计划
光影少年13 天前
RN 样式特点:Flex 布局默认、没有像素单位、样式不能级联
react native·react.js·掘金·金石计划
光影少年20 天前
react navite JSBridge 通信机制、异步通信特点
react native·react.js·掘金·金石计划
光影少年1 个月前
react批量更新、同步/异步更新场景
前端·react.js·掘金·金石计划