001-HTTP缓存机制

全面解析HTTP缓存机制:从浏览器缓存到代理缓存

1. 缓存体系概述

HTTP缓存体系主要分为三类:

  • 浏览器缓存(私有缓存):存储在用户浏览器中,仅对单个用户有效
  • 代理缓存(共享缓存):位于客户端和服务器之间的缓存(如CDN、反向代理、网关等),可为多个用户提供服务
  • 混合缓存:Service Worker等现代混合缓存机制

2. 强缓存(本地+代理)

强缓存阶段不发送请求到源服务器,直接使用缓存副本。

控制字段

Cache-Control (HTTP/1.1)

  • public:响应可被任何缓存(包括浏览器和代理)存储
  • private:响应只能被浏览器缓存(不允许代理缓存)
  • max-age=<seconds>:缓存有效期(相对时间)
  • s-maxage=<seconds>专门设置代理缓存的有效期(优先级高于max-age)
  • no-store:禁止任何缓存
  • no-cache:不使用强缓存,立即进入协商缓存
  • immutable:资源永不变(仅限浏览器缓存)

Expires (HTTP/1.0)

  • 绝对过期时间(如Expires: Thu, 31 Dec 2037 23:55:55 GMT
  • 缺点:依赖客户端时间同步

代理缓存特殊处理

1
Cache-Control: public, max-age=3600, s-maxage=7200

表示:

  • 浏览器缓存1小时(3600秒)
  • 代理缓存2小时(7200秒)

强缓存生效流程

1
2
3
4
graph TD
A[请求资源] --> B{缓存是否存在且有效}
B -->|是| C[直接使用缓存]
B -->|否| D[向服务器发起请求]

3. 协商缓存

当强缓存失效时,客户端携带验证信息向服务器确认资源有效性。

验证机制

1. Last-Modified / If-Modified-Since

  • 服务器响应头Last-Modified: <day-name>, <day> <month> <year> <hour>:<minute>:<second> GMT
    • 生成方式:文件系统中资源的最后修改时间
  • 客户端请求头If-Modified-Since: <Last-Modified-value>
    • 流程:如果服务器资源修改时间 > 客户端提供的值,则返回新资源(200);否则返回304

2. ETag / If-None-Match

  • 服务器响应头ETag: <etag_value>
    • 生成方式:
      • 强ETag:字节级匹配(如"5d83c2-55e-7f7163f3b5d00"
      • 弱ETag:语义匹配(如W/"5d83c2-55e-7f7163f3b5d00"
    • 常见生成算法:
      1
      2
      # Nginx配置示例(默认使用弱校验)
      etag on; # 默认基于最后修改时间+内容长度计算
      1
      # Apache默认使用inode+修改时间+大小
  • 客户端请求头If-None-Match: <etag_value>
    • 流程:服务器计算当前ETag与客户端值匹配则返回304,否则返回200

对比分析

维度 ETag Last-Modified
精确度 高(内容变化即可检测) 低(1秒内修改无法感知)
性能消耗 高(需读取完整内容) 低(仅文件属性)
分布式问题 无(内容决定) 有(服务器时间需同步)
优先级 高(两者共存时优先使用)
典型场景 频繁修改的小文件(如API) 大型静态文件

协商缓存流程

1
2
3
4
5
6
7
8
9
sequenceDiagram
participant Client
participant Server
Client->>Server: GET /resource <br> If-None-Match: "abc123" <br> If-Modified-Since: Wed, 21 Oct 2025 07:28:00 GMT
alt 资源未修改
Server-->>Client: 304 Not Modified <br> (空Body)
else 资源已修改
Server-->>Client: 200 OK <br> Last-Modified: ... <br> ETag: "def456" <br> [Resource Data]
end

304状态码详解

  • 语义:Not Modified(资源未修改)
  • 特点
    • 无响应体(节省带宽)
    • 必须包含更新的缓存头(如Date等)
  • 效果:指示客户端重用现有缓存

4. 缓存策略实践场景

不同资源类型的缓存配置

资源类型 推荐策略 场景说明
HTML文档 Cache-Control: no-cache + ETag 内容频繁更新,需及时验证
哈希版本JS/CSS Cache-Control: max-age=31536000, immutable 文件名含哈希,内容永不变
静态媒体资源 Cache-Control: public, max-age=604800 图片/字体等变更较少
API响应 Cache-Control: private, max-age=600 + ETag 用户私有数据,中等新鲜度要求
CDN托管资源 Cache-Control: public, max-age=86400, s-maxage=2592000 代理缓存比浏览器缓存更久

5. 预加载技术

<link rel="preload">

目的:声明当前页面关键资源,提前加载

1
2
<!-- 预加载关键字体 -->
<link rel="preload" href="font.woff2" as="font" type="font/woff2" crossorigin>

特点

  • 资源优先级提升为High
  • 必须指定as属性(font/image/script/style等)
  • 浏览器立即发起请求

<link rel="prefetch">

目的:预测用户下一步操作,提前缓存资源

1
2
<!-- 预取下一页资源 -->
<link rel="prefetch" href="next-page.html" as="document">

特点

  • 优先级为Lowest
  • 浏览器空闲时加载
  • 缓存时间短(Chrome默认5分钟)

使用场景对比

技术 最佳场景 风险提示
preload 关键渲染路径资源(首屏字体/关键CSS) 过度使用会挤占带宽
prefetch 用户可能访问的下一页(产品详情/文章页) 预测错误导致资源浪费

6. Service Worker缓存

核心能力

  • 完全控制网络请求(拦截/修改/缓存)
  • 离线运行能力
  • 后台同步

缓存策略实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 示例:Stale-While-Revalidate策略
self.addEventListener('fetch', event => {
event.respondWith(
caches.open('runtime-cache').then(cache => {
return cache.match(event.request).then(cachedResponse => {
const fetchPromise = fetch(event.request).then(networkResponse => {
cache.put(event.request, networkResponse.clone());
return networkResponse;
});
return cachedResponse || fetchPromise;
});
})
);
});

典型应用场景

  1. 离线应用:缓存核心资源实现离线访问
  2. 性能优化:缓存API响应提升二次访问速度
  3. 降级方案:网络不可用时提供基础功能
  4. 资源更新:后台静默更新缓存资源

7. 代理缓存详解

工作特性

  • 位置:客户端与源服务器之间
  • 优势
    • 减少源服务器负载
    • 降低网络延迟(就近访问)
    • 抵御流量高峰
  • 缓存控制
    • 遵循Cache-Controlpublic/s-maxage指令
    • 可忽略Vary头(某些代理)

代理缓存失效

  1. 传统方式:等待缓存过期
  2. 主动清除
    • CDN管理界面清除缓存
    • 通过API触发刷新(如POST /purge
  3. 内容变更
    • 修改URL(推荐)
    • 使用缓存破坏参数(需配置代理支持)

8. 高级缓存问题

缓存中毒(Cache Poisoning)

  • 成因:代理缓存存储了包含用户特定信息的响应
  • 防御
    • 正确设置Vary头(如Vary: Cookie, User-Agent
    • 敏感内容使用private

多版本资源处理

1
Vary: Accept-Encoding, User-Agent

指示代理根据Accept-EncodingUser-Agent字段缓存不同版本资源

总结:缓存优先级与决策树

优先级总则

  1. Cache-Control > Expires
  2. ETag > Last-Modified
  3. s-maxage > max-age(对代理缓存)

缓存决策流程

1
2
3
4
5
6
7
8
9
graph TD
A[请求资源] --> B{是否存在有效强缓存}
B -->|是| C[返回200 from cache]
B -->|否| D{是否配置协商缓存}
D -->|否| E[从服务器获取]
D -->|是| F[发送验证请求]
F --> G{服务器验证}
G -->|未修改| H[返回304使用缓存]
G -->|已修改| I[返回200新资源]

掌握HTTP缓存机制是Web性能优化的核心技能。合理配置浏览器缓存、代理缓存和Service Worker缓存,配合预加载技术,可显著提升用户体验并降低服务器成本。