网络2️⃣HTTP-缓存
对于一些具有重复性的 HTTP 请求(e.g. 每次请求得到的响应数据相同),
可以将这对请求-响应的数据缓存在本地,下次可直接读取本地数据,无需经过网络请求。
-
缓存作用:减少请求次数,提高性能。
-
实现方式:强制缓存、协商缓存
1、强制缓存
强制缓存:由浏览器决定是否使用缓存。
浏览器判断缓存是否过期,没过期则直接使用本地缓存。
示例:返回 200 状态码,size 项标识 from disk cache
。👉 说明使用了强制缓存。
1.1、实现
两种实现方式,分别对应两个 HTTP 首部字段。
首部的含义是资源在客户端缓存的有效期。
- Cache-Control(通用首部):相对时间,需要计算是否缓存过期。
- Expires(实体首部):绝对时间,可直接判断缓存过期。
如果响应报文的首部中同时有 Cache-Control 和 Expires,
Cache-Control 优先级更高。
1.2、Cache-Control 🔥
Cache-Control 选项更多,设置更加精细,更推荐使用。
实现流程:
-
浏览器:第一次请求访问服务器资源。
-
服务器:返回资源,在响应报文的首部添加 Cache-Control(设置过期时间大小);
-
浏览器:再次请求访问服务器中的该资源时
- 结合请求时间与 Cache-Control 设置的过期时间,计算资源是否过期,没过期则继续使用该缓存。
- 过期则重新请求服务器。
-
服务器:再次收到请求后,更新响应报文中首部的 Cache-Control。
2、协商缓存
协商缓存:由服务端告知客户端是否可以使用缓存。
浏览器与服务端协商之后,根据协商结果来判断是否使用本地缓存。
示例:响应码 304 Not Modified
。👉 服务器告诉浏览器可以使用本地缓存的资源。
2.1、基于时间实现
2.1.1、相关 HTTP 首部
Last-Modified
(实体首部):代表响应资源的最后修改时间(更新时间)。If-Modified-Since
(请求首部):代表客户端要比较资源的 Last-Modified。
2.1.2、实现
- 浏览器:第一次请求访问服务器资源。
- 服务器:返回资源,并在响应报文首部添加
Last-Modified
。 - 浏览器:发现响应报文首部中有
Last-Modified
,再次发起请求的时候带上If-Modified-Since
(值为响应报文的Last-Modified
时间)。 - 服务器:收到请求后发现有
If-Modified-Since
,对比资源的更新时间(Last-Modified
)- 如果当前更新时间较新(大):说明资源在客户端上次缓存之后又被改过,响应 200 OK 和最新资源,并在响应报文首部添加新的
Last-Modified
。 - 否则说明资源无新修改,响应 304 告知浏览器走缓存。
- 如果当前更新时间较新(大):说明资源在客户端上次缓存之后又被改过,响应 200 OK 和最新资源,并在响应报文首部添加新的
基于时间实现的协商缓存,可能会因为时间篡改导致不可靠。
2.2、基于唯一标识实现 🔥
此方式必须配合强制缓存的
Cache-Control
使用,当强制缓存未命中时,才进行协商缓存。
2.2.1、相关 HTTP 首部
Etag
(响应首部):唯一标识响应资源。If-None-Match
(请求首部):代表客户端要比较资源的 Etag。
2.2.2、实现
- 浏览器:第一次请求访问服务器资源。
- 服务器:返回资源,并在响应报文首部添加
Etag
。 - 浏览器:
- 强:先检查强制缓存是否过期,没过期则使用强制缓存;过期则进行协商缓存(即以下的后续步骤)。
- 协商:发现响应报文首部中有
Etag
,再次发起请求时带上If-None-Match
(值为 Etag 值)。
- 服务器:收到请求后发现有
If-None-Match
,比对资源的 Etag。- 如果 Etag 不同:说明资源改变,响应 200 OK 和最新资源,并在响应报文首部添加新的
Etag
。 - 否则说明资源无改变,响应 304 告知浏览器走缓存。
- 如果 Etag 不同:说明资源改变,响应 200 OK 和最新资源,并在响应报文首部添加新的
2.2.3、优先级
如果响应报文的首部中同时有 Last-Modified 和 Etag,
Etag 优先级更高:先判断 Etag 是否变化,再判断 Last-Modified。
原因:ETag 能解决 Last-Modified 难以解决的问题。
- 即使文件内容不变,Last-Modified 也可能改变。👉 此时客户端认为文件改动,从而重新请求。
- 文件可能在秒级以内修改的。👉
If-Modified-Since
的检查粒度是秒级,Etag
是毫秒级。 - 👉 部分服务器无法精确获取文件的
Last-Modified
。
附:Cache-Control 指令参数
Cache-Control
(通用首部字段)
- 指令参数可选的。
- 多个参数之间用
,
分隔。 - 请求报文和响应报文中有相同的参数,且含义可能不同。
共有
- no-cache:防止使用过期的缓存(而不是不缓存)
- 请求报文:客户端不接收缓存过的响应,缓存服务器必须把请求转发给源服务器。
- 响应报文:源服务器要求缓存服务器不对资源进行缓存。
- no-store:不使用缓存
- max-age:
- 请求报文:客户端只接收缓存时间比 max-age 值小的缓存资源(0 表示缓存服务器需要将请求转发给源服务器)。
- 响应报文:缓存服务器不对资源有效性再作确认(max-age 值为缓存资源的最长保存时间)。
- no-transform:缓存不能改变实体主体的媒体类型,用于防止压缩编码等操作。
- cache-extension:扩展 Cache-Control 的首部字段内的指令。
请求报文独有
- max-stale:即使缓存资源过期,也照常接收。
- min-fresh:客户端要求缓存服务器,返回指定时间以内的缓存资源。
- only-if-cached:请求的资源在缓存服务器的本地缓存时,客户端才要求其返回。
(即如果缓存服务器中没有请求资源的缓存,则不会转发请求给源服务器)
响应报文独有
- public:任何用户都可以使用响应的缓存
- private:指定用户才能使用响应的缓存
- 缓存服务器对特定用户提供资源缓存的服务
- 对其它用户发送的请求,不会返回缓存
- s-maxage:与 max-age 相同,但是 s-maxage 仅用于多用户使用的公共缓存服务器。
- must-revalidate:要求代理在返回缓存资源之前,向源服务器再次验证缓存是否仍有效
- proxy-revalidate:类似 must-revalidate,但只适用于共享缓存,不影响私有缓存。