HTTP缓存
本文最后更新于:8 个月前
本文介绍了http缓存的工作流程,强缓存、协商缓存的工作机制和重要字段。以及介绍了「代理缓存&本地缓存」、「下行缓存&上行缓存」、「内存缓存&磁盘缓存」的概念
HTTP缓存
http缓存机制分为强缓存、协商缓存两种
- 强缓存,判断缓存中的资源是否过期,没有过期,直接获取缓存资源;否则请求服务器资源
- 协商缓存,通过在请求中携带特殊字段(If-Modified-Since或If-None-Match)向服务器询问缓存中的资源是否发生改变,没有改变,重定向到缓存获取缓存中的资源;如果改变了,请求服务器的资源
http两种缓存的工作流程
一、强缓存
利用http头中的Expires(http1.0)和Cache-Control(http1.1)两个字段来控制的。强缓存中,当请求再次发出时,浏览器会根据其中的Expires和Cache-Control判断目标资源是否“命中”强缓存,如果命中则直接从缓存中获取资源,不会再与服务端发生通信。命中强缓存的情况下,返回的HTTP状态码为200。
如下图中,返回的是 200 状态码,但在 size 项中标识的是 from disk cache,就是使用了强制缓存
Cache-Control
(http1.1), 是一个相对时间;Expires
(http1.0),是一个绝对时间;优先级:
Cache-Control
>Expires
expires是HTTP1.0的产物。当服务器返回响应时,在Response Headers中将过期时间写入Expires字段。浏览器通过对比本地时间和过期时间,判断资源是否过期。
Cache-Control是HTTP1.1提出的特性。
Cache-Control包含的值很多:
值 | 说明 |
---|---|
public | 表明响应可以被任何对象(包括:发送请求的客户端、代理服务器等等)缓存 |
private | 表明响应只能被客户端缓存 |
no-cache | 跳过强缓存,直接进入协商缓存阶段 |
no-store | 表示当前请求资源禁用缓存 |
max-age= | 设置缓存存储的最大周期,超过这个时间缓存被认为过期(单位秒) |
s-maxage= | 覆盖max-age或者Expires头。如果s-maxage未过期,则向代理服务器请求其缓存内容。 |
这里需要注意的是:s-maxage仅在代理服务器中生效,客户端只需要考虑max-age。
- 当浏览器第一次请求访问服务器资源时,服务器会在返回这个资源的同时,在 Response 头部加上 Cache-Control,Cache-Control 中设置了过期时间大小;
- 浏览器再次请求访问服务器中的该资源时,会先通过请求资源的时间与 Cache-Control 中设置的过期时间大小,来计算出该资源是否过期,如果没有,则使用该缓存,否则重新请求服务器;
- 服务器再次收到请求后,会再次更新 Response 头部的 Cache-Control
二、协商缓存
协商缓存,也称为对比缓存。协商缓存机制下,浏览器需要向服务器去询问缓存的相关信息,进而判断是重新发起请求、下载完整的响应,还是从本地获取缓存的资源。
如果服务端提示缓存资源未改动(Not Modified),资源会被重定向到浏览器缓存,这种情况下网络请求对应的状态码是 304(如下图)。
控制协商缓存的字段分别有:Last-Modified和Etag,其中Etag的优先级比Last-Modified高
方式一:Last-Modified + If-Modified-Since
- 服务器返回资源时,在响应头附上
Last-Modified
字段,表示资源的最后修改时间 - 客户端发送请求时,当资源过期后,如果发现响应头中有
Last-Modified
声明(一个时间戳),则发送请求时,通过If-Modified-Since
携带上这个时间戳,与服务器上的资源的Last-Modified
字段进行对比 - 如果资源被修改了,返回新资源;如果没有新修改,返回304状态码
Last-Modified(Response Header)和If-Modified-Since(Request Header)是一对报文头,属于HTTP1.0。
Last-Modified表示资源的最后修改时间,是一个时间戳,如果启用了协商缓存,它会在首次请求时随着Response Headers返回。
1 |
|
If-Modified-Since是一个请求首部字段,并且只能用在GET或HEAD请求中。客户端再次请求服务器时,请求头会包含这个字段,后面跟着在缓存中获取的资源的最后修改时间。
1 |
|
服务端收到请求发现此请求头中有If-Modified-Since字段,会与被请求资源的最后修改时间进行对比,如果一致则会返回304和响应报文头,浏览器从缓存中获取数据即可。从字面上看,就是说从某个时间节点开始看,是否被修改了,如果被修改了,就返回整个数据和200 OK,如果没有被修改,服务端只要返回响应头报文,304 Not Modified,Response Headers不会再添加Last-Modified字段。
方式二:Etag + If-None-Match
Etag是一个响应首部字段,是根据实体内容生成的一段hash字符串,标识资源的状态,由服务端产生。
1 |
|
If-None-Match是一个条件式的请求首部,如果请求资源时在请求首部加上这个字段,值为之前服务器返回的Etag,则当且仅当服务器上没有任务资源的Etag属性值与这个值相符,服务器才会返回带有请求资源实体的200响应,否正服务器会返回不带实体的304响应。
1 |
|
Etag 的生成过程需要服务器额外付出开销,会影响服务端的性能,这是它的弊端。Etag 并不能替代 Last-Modified,它只能作为 Last-Modified 的补充和强化存在
优先级:Etag > Last-Modified
如果在第一次请求资源的时候,服务端返回的 HTTP 响应头部同时有 Etag 和 Last-Modified 字段,那么客户端再下一次请求的时候,如果带上了 ETag 和 Last-Modified 字段信息给服务端,
这时,服务端先会判断 Etag 是否变化了,如果 Etag 有变化就不用在判断 Last-Modified 了,如果 Etag 没有变化,然后再看 Last-Modified。
顺序:先强制,再协商
协商缓存这两个字段都需要配合强制缓存中 Cache-control 字段来使用,只有在未能命中强制缓存的时候,才能发起带有协商缓存字段的请求。
例如:使用 ETag 字段实现的协商缓存的过程:
当浏览器第一次请求访问服务器资源时,服务器会在返回这个资源的同时,在 Response 头部加上 ETag 唯一标识,这个唯一标识的值是根据当前请求的资源生成的;
当浏览器再次请求访问服务器中的该资源时,首先会先检查强制缓存是否过期:
- 如果没有过期,则直接使用本地缓存;
- 如果缓存过期了,会在 Request 头部加上 If-None-Match 字段,该字段的值就是 ETag 唯一标识;
服务器再次收到请求后,
会根据请求中的 If-None-Match 值与当前请求的资源生成的唯一标识进行比较
- 如果值相等,则返回 304 Not Modified,不会返回资源;
- 如果不相等,则返回 200 状态码和返回资源,并在 Response 头部加上新的 ETag 唯一标识;
如果浏览器收到 304 的请求响应状态码,则会从本地缓存中加载资源,否则更新资源。
三、缓存控制字段
1、可缓存性控制
cache:public
,表明响应资源可以被所有对象缓存,如浏览器、代理服务器等cache:private
,表明响应资源只能被浏览器缓存cache:no-cache
,跳过强缓存阶段、直接进入协商缓存阶段,即需要向服务器验证缓存有效性cache:no-store
,禁用缓存
2、缓存有效性控制
max-age=秒数
,设置缓存储存的最大期限,超过这个时间表示缓存过期s-maxage=秒数
,和max-age
相同的作用,只不过仅仅适用于代理服务器max-stale[=秒数]
,(在请求头中添加),表示浏览器愿意接受一个过期的缓存资源,可以选择添加时间,表示愿意接受的范围min-fresh=秒数
,(在请求头中添加),表示客户端希望获取一个能在指定的秒数内保持其最新状态的响应stale-while-revalidate=
, 表明客户端愿意接受陈旧的响应,同时在后台异步检查新的响应。秒值指示客户愿意接受陈旧响应的时间长度。stale-if-error=
,表示如果新的检查失败,则客户愿意接受陈旧的响应。秒数值表示客户在初始到期后愿意接受陈旧响应的时间。
3、重新加载 / 验证控制
must-revalidate
,一旦资源过期(比如已经超过max-age),在成功向原始服务器验证之前,缓存不能用该资源响应后续请求。proxy-revalidate
,与must-revalidate作用相同,但它仅适用于共享缓存(例如代理),并被私有缓存忽略
4、其它控制
- no-transform,(响应头中使用),不得对资源进行转换或转变,一般用于限制代理服务器
only-if-cached
,(请求头中使用),表明客户端只接受已缓存的响应,并且不要向原始服务器检查是否有更新的拷贝
5、组合控制
cache-control可以同时接受多个取值的。可缓存性控制+缓存有效性控制+其他控制 ,这几个控制维度是不冲突的,可以共同实现缓存的实现方式限定。
当不同字段发生冲突时,按照优先级进行取舍
四、代理服务器缓存 & 本地缓存
代理服务器缓存,就是保存在代理服务器上的缓存资源,可以减少直接请求源服务器造成的压力
本地缓存,就是保存在浏览器本地的缓存资源,在减少服务器压力的基础上,还可以提高资源加载速度,优化用户体验
设置为cache-control:public
,代理服务器和浏览器客户端都可以缓存资源;设置为cache-control:private
,只有浏览器客户端可以缓存资源。
五、下行缓存 & 上行缓存
下行缓存,就是通过在响应头设置cache-control
缓存控制字段,即在nginx或者其它代理上设置控制字段。
上行缓存,就是在http请求头中设置缓存控制字段,一般用的较少。
六、内存缓存 & 磁盘缓存
根据缓存存放位置,可以分为:「Memory cache」内存缓存、「Disk cache」硬盘缓存
1、内存缓存的特点
- 读取速度快
- 一旦关闭Tab页、或者关闭浏览器,内存就会被释放
2、硬盘缓存的特点
- 读取速度慢一点
- 储存时间长
Q:怎么去区分一个资源是该缓存到内存中、还是缓存到硬盘中呢?
3、储存形式
以上两者的存储形式为一个index.dat文件,记录存储数据的url,然后再分别存储该url的response信息和content内容。
Response信息最大作用就是用于判断服务器上该url的content内容是否被修改。
参考文章: