HTTP协议--缓存
HTTP协议--缓存
HTTP为什么需要缓存
对于具有重复性的HTTP请求(例如部分GET,HEAD请求),在服务端没有修改数据的情况下,每次请求的结果是一样的,因此可以把[请求-响应]数据缓存在本地,避免访问服务器,提高性能
HTTP缓存有两种实现方法,分别是强制缓存和协商缓存
强制缓存
强制缓存通过 Cache-Control 或 Expires 响应头实现。浏览器或客户端在缓存有效期内直接从本地读取资源,不向服务器发起请求。
HTTP 缓存中强制缓存的启用由服务端决定
客户端(如浏览器)仅根据服务端返回的响应头执行缓存策略
- no-cache:客户端要求服务器验证资源是否过期(强制走协商缓存)。
- max-age=0:客户端要求缓存立即过期(强制走协商缓存)。
- no-store:客户端明确禁止缓存(既不强制缓存,也不协商缓存)。
Cache-Control与Expires比较
- Cache-Control: max-age=N
- 计算方式: 过期时间 = 资源获取时间 + max-age(秒)
- Expires: <日期> 日期>
- 过期时间 = Expires 头中指定的绝对时间(GMT 格式)。
- 示例:
Expires : Thu, 01 Oct 2023 13:00:00 GMT
Cache-Control 更优
- 相对时间不受客户端时钟影响,更可靠。
- 支持更多缓存控制指令(如 no-cache, must-revalidate)。
- 现代Web开发首选
Expires局限性
- 依赖客户端和服务端时钟严格同步,否则缓存时间计算可能错误。
- 已被 Cache-Control 取代,仅用于兼容旧系统。
实现过程:
- 客户端(浏览器)向服务端发送请求
- 服务端返回资源,在头部加上
Cache-Control: max-age=N告诉客户端资源过期时间(相对时间) - 客户端再次请求访问服务器中的该资源时,会根据赏赐访问的时间辍+
Cache-Control中过期时间与现在时间比较,确认资源是否过期,如果没有,直接使用本地缓存,如果没有,重新请求服务器 - 服务器再次受到请求后,会更新
Cache-Control
协商缓存
协商缓存就是与服务端协商之后,通过协商结果来判断是否使用本地缓存。
协商缓存可以使用两种头部实现
第一种:请求头部的If-Modified-Since字段与响应头部的Last_modified字段实现,这两个字段的作用:
- 响应头部中的 Last-Modified:标示这个响应资源的最后修改时间;
- 请求头部的
If-Modified-Since:当资源过期了而之前的响应头中具有Last-Modified声明,则请求时会将这个值赋给If-Modified-Since.服务段收到后与资源的实际修改时间比较,如果最后修改时间较新(大),说明资源修改过,返回最新资源,否则返回状态码304,浏览器使用本地缓存
第二种:请求头部中的If-None-Match字段与响应头部的Etag字段,这两个字段的作用:
- 响应头部的
Etag:唯一标识响应资源 - 请求头部中的
If-None-Match:当资源过期时,浏览器发现响应头中有Etag字段,则再次向服务器发起请求时,会将请求头If-None-match值设为Etag的值,服务器收到后与资源比较,如果资源没有变化返回状态名304,如果变化则返回200和最新的资源
如果请求同时具有
If-Modified_Since和If-None-Match后者的优先级更高
为什么Etag优先级更高
- 在没有修改文件内容的情况下文件最后修改时间可能也会改变,者会导致客户端认为文件被改动了,从而重新请求
- 可能有些文件是在秒级以内修改的,
If-Modified-Since能检查到粒度是秒级的,使用Etag能保证在这种需求下客户端在1秒能刷新多次 - 有些服务器不能精确获取文件的最后修改时间
强制缓存和协商缓存的协作
强制缓存优先:
- 如果资源在强制缓存有效期内(未过期),客户端直接使用本地缓存,不发送请求。
- 如果资源过期,客户端才会发起请求,并进入协商缓存流程。
协商缓存作为兜底验证
- 当强制缓存失效后,客户端会在请求头中携带 If-None-Match(对应 ETag)或 If-Modified-Since(对应 Last-Modified)。
- 如果服务器返回 304 Not Modified,客户端更新缓存有效期(例如重置 max-age),继续使用本地缓存。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
客户端发起请求
│
▼
┌───────────────────┐
│ 检查强制缓存是否有效 │
└─────────┬─────────┘
│
┌─────────▼─────────┐ ┌───────────────┐
│ 缓存有效? ├─Yes───────────► 直接使用缓存 │
└─────────┬─────────┘ └───────────────┘
│No
▼
┌───────────────────┐
│ 发送请求,并携带验证头 │
│(If-None-Match等) │
└─────────┬─────────┘
│
┌─────────▼─────────┐ ┌───────────────┐
│ 服务器验证资源是否变化 ├─No───────────► 返回304,更新缓存 │
└─────────┬─────────┘ └───────────────┘
│Yes
▼
┌───────────────────┐
│ 返回200和新资源 │
└───────────────────┘
This post is licensed under CC BY 4.0 by the author.
.png)
.png)