HTTP 缓存策略
强缓存和协商缓存的工作原理、区别及应用场景
问题
HTTP 缓存策略有哪些,它们有什么区别,分别解决了什么问题?
解答
缓存机制概述
浏览器缓存分为强缓存和协商缓存两种,强缓存优先级更高。缓存从第二次请求开始生效:
- 第一次请求时,服务器返回资源和缓存策略(通过 response header)
- 第二次请求时,浏览器先检查强缓存,命中则直接返回 200;未命中则发送请求头到服务器验证协商缓存,命中返回 304
强缓存
强缓存命中时直接读取本地资源,不发送请求,Network 面板显示 from memory cache 或 from disk cache。
Expires(HTTP/1.0)
服务器返回一个绝对过期时间:
Expires: Mon, 10 Nov 2024 09:10:11 GMT
优点: 简单易用,兼容 HTTP/1.0
缺点:
- 依赖客户端时间,时间不同步会导致缓存失效
- 无法感知到期前的资源更新
Cache-Control(HTTP/1.1)
使用相对时间,优先级高于 Expires:
Cache-Control: max-age=3600
常用指令:
# 可缓存性
Cache-Control: public # 客户端和代理服务器都可缓存
Cache-Control: private # 仅客户端可缓存(默认值)
Cache-Control: no-cache # 需要验证后才能使用缓存
Cache-Control: no-store # 完全不缓存
# 过期时间
Cache-Control: max-age=3600 # 缓存有效期 3600 秒
Cache-Control: s-maxage=7200 # CDN 等共享缓存的有效期
Cache-Control: must-revalidate # 过期后必须向服务器验证
优点:
- 使用相对时间,避免时间不同步问题
- 提供丰富的缓存控制选项
缺点: 无法感知到期前的资源更新
协商缓存
强缓存失效后,浏览器携带缓存标识向服务器验证资源是否更新。服务器返回 304 表示未修改,浏览器使用本地缓存;返回 200 则返回新资源。
Last-Modified / If-Modified-Since(HTTP/1.0)
服务器首次返回资源的最后修改时间:
Last-Modified: Mon, 10 Nov 2024 09:10:11 GMT
浏览器再次请求时携带该时间:
If-Modified-Since: Mon, 10 Nov 2024 09:10:11 GMT
服务器对比时间,相同返回 304,不同返回 200 和新资源。
优点: 每次请求都会验证,避免使用过期资源
缺点:
- 只要文件修改就返回新资源,即使内容未实质变化
- 精度只到秒,无法识别 1 秒内的多次修改
- 动态生成的文件每次修改时间都不同,无法有效缓存
ETag / If-None-Match(HTTP/1.1)
服务器返回资源的唯一标识(通常是内容 hash):
ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4"
浏览器再次请求时携带该标识:
If-None-Match: "33a64df551425fcc55e4d42a148795d9f25f89d4"
服务器对比 ETag,相同返回 304,不同返回 200 和新资源。ETag 优先级高于 Last-Modified。
优点:
- 基于内容判断,更精确
- 可识别 1 秒内的多次修改
缺点:
- 计算 hash 有性能开销
- 分布式环境下不同服务器的 ETag 算法可能不一致
缓存策略示例
# 静态资源(带版本号):强缓存 1 年
Cache-Control: public, max-age=31536000, immutable
# HTML 文件:协商缓存
Cache-Control: no-cache
# API 接口:不缓存
Cache-Control: no-store
关键点
- 强缓存直接使用本地资源不发请求,协商缓存需要向服务器验证返回 304 或 200
- Cache-Control 优先级高于 Expires,ETag 优先级高于 Last-Modified
- Expires 使用绝对时间存在时间不同步问题,Cache-Control 使用相对时间解决了这个问题
- Last-Modified 精度只到秒且基于修改时间,ETag 基于内容 hash 更精确但有计算开销
- 实际应用中通常组合使用:静态资源用强缓存,HTML 用协商缓存,API 不缓存
目录