HTTP 缓存机制概述
HTTP 缓存机制通过在客户端或代理服务器上存储响应数据,以减少网络延迟和服务器负载,从而加快网页加载速度。缓存机制主要涉及两个策略:强缓存和协商缓存。
强缓存
强缓存是指客户端在缓存有效期内直接使用缓存的数据,而不向服务器发送请求。
协商缓存
协商缓存是指客户端每次请求资源时,都会向服务器发送验证请求,以确认缓存的数据是否仍然有效。如果有效,则服务器返回 304(Not Modified),客户端继续使用缓存数据;否则,服务器返回新的资源数据。
客户端与服务端的交互过程
1. 初次请求
当客户端(如浏览器)首次请求某个资源时,服务器会返回资源数据及缓存相关的头部信息:
请求
GET /resource HTTP/1.1
Host: www.example.com
响应
HTTP/1.1 200 OK
Date: Mon, 08 Jun 2024 10:00:00 GMT
Cache-Control: max-age=3600, must-revalidate
Last-Modified: Wed, 21 Oct 2020 07:28:00 GMT
ETag: "686897696a7c876b7e"
Content-Type: text/html
Content-Length: 1234
<html>...</html>
在这个响应中:
Cache-Control: max-age=3600指示资源可以被缓存 3600 秒(1 小时)。Last-Modified和ETag提供了资源的最后修改时间和实体标签,用于后续的协商缓存请求。
2. 强缓存
在缓存有效期内(1 小时内),客户端再次请求相同资源时,会直接从缓存中获取数据,而不会向服务器发送请求。
请求
(客户端从缓存中读取,无需与服务器交互)
3. 协商缓存
当缓存过期后,客户端再次请求相同资源时,会向服务器发送验证请求,检查缓存数据是否仍然有效。
请求
GET /resource HTTP/1.1
Host: www.example.com
If-Modified-Since: Wed, 21 Oct 2020 07:28:00 GMT
If-None-Match: "686897696a7c876b7e"
在这个请求中:
If-Modified-Since包含上次响应的Last-Modified时间。If-None-Match包含上次响应的ETag值。
响应(资源未修改)
如果资源未修改,服务器返回 304 状态码,并不包含响应体。
HTTP/1.1 304 Not Modified
Date: Mon, 08 Jun 2024 11:05:00 GMT
客户端收到 304 响应后,会继续使用缓存的数据。
响应(资源已修改)
如果资源已修改,服务器返回新的资源数据和相应的缓存头部信息。
HTTP/1.1 200 OK
Date: Mon, 08 Jun 2024 11:05:00 GMT
Cache-Control: max-age=3600, must-revalidate
Last-Modified: Mon, 08 Jun 2024 11:00:00 GMT
ETag: "9b3a4f5a7d8e2f7c9a"
Content-Type: text/html
Content-Length: 1256
<html>...</html>
在这个响应中,Last-Modified 和 ETag 值会被更新,客户端会用新的数据替换旧的缓存数据。
总结
1. 初次请求
客户端请求资源,服务器返回资源数据和缓存头部信息。
2. 强缓存
在缓存有效期内,客户端直接从缓存中获取数据,不向服务器发送请求。
3. 协商缓存
缓存过期后,客户端发送验证请求,服务器根据资源是否修改返回相应的状态码:
- 304(Not Modified):客户端继续使用缓存数据。
- 200(OK):服务器返回新的资源数据和缓存头部信息,客户端更新缓存。
通过这种机制,HTTP 缓存有效地减少了不必要的网络请求,提高了资源加载速度和用户体验。理解客户端与服务器之间的交互过程,有助于更好地配置和利用缓存机制。
4. 两者对比优先级
在 HTTP 缓存中,优先级决定了缓存机制的适用顺序以及缓存策略的使用顺序。主要的优先级关系是基于 HTTP 头部字段的组合和具体策略。以下是详细的优先级解释:
优先级原则
1. 明确的禁止缓存指令
如果响应中包含明确的禁止缓存指令,如 Cache-Control: no-store,则这些指令具有最高优先级。无论其他缓存头部如何设置,响应都不会被缓存。
Cache-Control: no-store
2. 强缓存指令
在没有禁止缓存指令的情况下,强缓存指令的优先级次之。这些指令包括 Cache-Control: max-age 和 Expires。其中,Cache-Control 的优先级高于 Expires。
Cache-Control
Cache-Control: max-age=3600
Expires
Expires: Wed, 21 Oct 2023 07:28:00 GMT
如果两者同时存在,Cache-Control 会覆盖 Expires:
Cache-Control: max-age=3600
Expires: Wed, 21 Oct 2023 07:28:00 GMT
3. 协商缓存
如果没有强缓存指令,或者强缓存已过期,协商缓存指令将生效。常用的协商缓存头部包括 Last-Modified 和 ETag,客户端会在请求中使用 If-Modified-Since 和 If-None-Match 进行验证。
Last-Modified
Last-Modified: Wed, 21 Oct 2020 07:28:00 GMT
ETag
ETag: "686897696a7c876b7e"
客户端请求中的条件头部
If-Modified-Since: Wed, 21 Oct 2020 07:28:00 GMT
If-None-Match: "686897696a7c876b7e"
4. 特殊的 Cache-Control 指令
某些 Cache-Control 指令会影响上述优先级,包括:
no-cache:强制客户端在使用缓存数据前验证资源的新鲜度。must-revalidate:缓存过期后,必须向服务器重新验证。
No-cache 示例
Cache-Control: no-cache
Must-revalidate 示例
Cache-Control: must-revalidate
客户端与服务端的交互过程
示例 1:禁止缓存
客户端请求资源,服务器返回响应并明确禁止缓存:
请求
GET /resource HTTP/1.1
Host: www.example.com
响应
HTTP/1.1 200 OK
Cache-Control: no-store
Content-Type: text/html
Content-Length: 1234
<html>...</html>
结果:客户端不会缓存响应数据。
示例 2:强缓存(Cache-Control 优先级高于 Expires)
服务器设置强缓存指令:
请求
GET /resource HTTP/1.1
Host: www.example.com
响应
HTTP/1.1 200 OK
Cache-Control: max-age=3600
Expires: Wed, 21 Oct 2023 07:28:00 GMT
Content-Type: text/html
Content-Length: 1234
<html>...</html>
结果:客户端缓存数据 3600 秒(1 小时),Cache-Control 优先于 Expires。
示例 3:协商缓存
强缓存过期后,客户端发起协商缓存请求:
初次请求
GET /resource HTTP/1.1
Host: www.example.com
初次响应
HTTP/1.1 200 OK
Cache-Control: max-age=10
Last-Modified: Wed, 21 Oct 2020 07:28:00 GMT
ETag: "686897696a7c876b7e"
Content-Type: text/html
Content-Length: 1234
<html>...</html>
强缓存过期后客户端请求
GET /resource HTTP/1.1
Host: www.example.com
If-Modified-Since: Wed, 21 Oct 2020 07:28:00 GMT
If-None-Match: "686897696a7c876b7e"
响应(资源未修改)
HTTP/1.1 304 Not Modified
Date: Mon, 08 Jun 2024 10:05:00 GMT
结果:服务器返回 304,客户端继续使用缓存数据。
示例 4:特殊 Cache-Control 指令
服务器响应中包含 no-cache 或 must-revalidate 指令:
请求
GET /resource HTTP/1.1
Host: www.example.com
响应
HTTP/1.1 200 OK
Cache-Control: no-cache
Last-Modified: Wed, 21 Oct 2020 07:28:00 GMT
ETag: "686897696a7c876b7e"
Content-Type: text/html
Content-Length: 1234
<html>...</html>
结果:客户端每次使用缓存前必须向服务器验证数据的新鲜度。
总结
HTTP 缓存的优先级从高到低依次为:
- 明确的禁止缓存指令(如
Cache-Control: no-store) - 强缓存指令(如
Cache-Control: max-age,优先于Expires) - 协商缓存(如
Last-Modified和ETag结合If-Modified-Since和If-None-Match) - 特殊 Cache-Control 指令(如
no-cache和must-revalidate)
了解这些优先级和交互过程,可以帮助开发者更好地控制缓存行为,提高 Web 应用的性能和用户体验。