HTTP系列:缓存

先看一些概念性的术语:

命中率:由缓存提供服务的请求所占的比例被称为缓存命中率;

缓存未命中:其实就是一些到达缓存的请求没有副本可用,而被转发给原始服务器;

再验证:原始服务器上内容可能会发生变化,缓存需要对副本进行检测,看是否为最新的,这种“新鲜度检测”叫HTTP再验证;

缓存主要分为两类:

一,私有缓存

私有缓存是用户个人的缓存,Web浏览器中有内建的私有缓存,大部分浏览器将内容缓存到个人电脑的磁盘和内存中。这些缓存用来提供浏览器向前/向后、保存网页、查看源代码、离线浏览等功能。

二,公有代理缓存

公有缓存是多个用户使用,它是特殊的共享代理服务器,被称为缓存代理服务器,或被称为代理缓存。

缓存的基本步骤:

1,接收;

2,解析:将请求报文解析为片段;

3,查找;

4,新鲜度检测;

5,创建响应;

6,发送;

7,日志;

一,判断缓存是否过期:

1,cache-control: max-age=15400

max-age表示多少时间后过期,单位秒,这里是相对时间,既可以作为请求头,也可以作为响应头,如果请求头中设置max-age=0,表示立即过期,会进行新鲜度的校验,详细见后文。

还有一个s-maxage,仅适用于共享(公共)缓存

2,expires: Tue, 30 Jul 2019 04:59:34 GMT

表示什么时间后过期,这里是绝对时间,取决于用户当前系统时间,因此不建议单以这个为过期标准。

一般情况下,建议使用cache-control: max-age头,相对时间更好一些,如果两个标识都有,那么必须两个都过期了才算过期。

二,如果过期了,会进行新鲜度的校验:

当缓存资源过期时,缓存会向原始服务器发送一个条件请求GET,因为虽然当前缓存资源已经过期,但也有可能资源依然没有变化,所以不一定需要重新去获取资源,这时候就要做新鲜度的校验,对比缓存资源是否需要更新。

1,If-Modified-Since/Last-modified:Thu, 30 May 2019 11:44:49 GMT

这两个是搭配使用的,前者是请求头,后者是响应头,第一次返回数据时,响应头里会包含Last-modified字段,用来表示最近一次更新时间,当缓存资源过期时,缓存就会发送一个条件请求GET,请求头里带有If-Modified-Since,值就是Last-modified之前返回的值,如果检测发现服务器上资源文件最近修改时间和请求头里的这个时间一致,则不需要更新缓存,返回304状态码,这时候响应主体里是不会带有资源内容的,因为不需要更新,所以不返回,并重新更新缓存时间,就是上面说的cache-control: max-age和expires。如果不一致,则重新返回新的资源内容以及最近修改时间,并设置过期时间,状态码200.

2,If-None-Match/Etags: W/"d343901e56dedb646942d7f8d2a7df87"

对于大部分场景,Last-modified是满足的,但是对于一些特殊场景,那么就有问题了:

1️⃣亚秒级别的资源更新,时间相关的,因为Last-modified只能精确到秒级,所以无法精准;

2️⃣对于一些资源的更新,如果只是更新了一些无关紧要的小内容,那其实没必要重新更新缓存资源,我们允许继续使用旧的缓存,那这时候实际上就是一种弱检查;

Etags会返回一段hash的字符串,用来标识当前资源,如果缓存过期,那么If-None-Match就会带上Etags第一次返回过来的值,然后去和服务器上的tag作对比,如果发现不一致,则重新返回资源并更新缓存,如果没有变化,则返回304,更新缓存过期时间。这里示例代码里加了一个W,就表示这是一条弱检查。

但是大部分场景,我们还是使用If-Modified-Since/Last-modified来判断是否需要更新过期资源。

三,强制更新或取消缓存

这里还是用到cache-control头,这里作为请求头

no-store:禁止使用缓存,清除缓存资源,重新去原始服务器上去获取资源;

no-cache:在进行新鲜度校验之前,不能使用缓存。和no-store不一样的是,no-cache并不是不缓存,而是缓存了但是不使用,在新鲜度校验成功后才可以使用缓存;

must-revalidate:在缓存资源过期之后,必须进行新鲜度校验,这里是必须过期之后才起作用;过期后强制校验;(没什么用)

 再补充一个stale-while-revalidate: 它表示允许缓存过期后的一段时间内继续使用,同时会发起一个异步新鲜度二次校验,如果资源更改了,那么下次访问的时候就能拿到一个新鲜的,但如果过期时间没有超过stale-while-revalidate给出的时间,第一次的时候一定是取的缓存,这种策略是用速度换取了内容的新鲜程度,需要谨慎使用。

这里补充一个Chrome里的知识点:

我们一般打开一张图片,如果是首次打开,这里就是一个正常的请求,状态码200,图片大小正常,size有值。

但是当我们关掉这个浏览器,再重新打开一个,再次访问刚刚的图片地址,状态码200,会发现这里的size变成了from disk cache,这里表示已经缓存到本地硬盘里中了,所以会直接读取硬盘里的缓存图片,然后返回的报文也是之前缓存的时候的报文。

当我们刷新这个页面,会发现状态码变成了304,size有值了,但是和第一次打开的时候不一样,那么根据之前讲的,304说明浏览器进行了缓存的新鲜度二次校验,那么我们可以猜测,浏览器在刷新的时候,会发一个cache-control: no-cache的请求,进行一个二次新鲜度校验,这里发现图片资源未改变,所以不会重新获取资源,而是继续读取本地缓存,所以状态码为304,而大小为什么不是原图大小,因为二次校验的时候,条件请求如果为否,则不会返回完整资源。

这里应该还有一个size情况是from memory cache,表示是从内存里读取的缓存,这里我没有找到截图,它和from disk cache的区别就是内存里的缓存优先级更高一些,但是如果浏览器关闭,则会清掉,而disk cache是永久性的,除非手动删除硬盘上的缓存,不然一直存在,浏览器关掉也在。所以整个校验流程是:

1,浏览器内存中读取缓存;

2,本地硬盘上读取缓存;

3,从服务器拉取数据,并缓存到本地硬盘和内存中;

end

原文地址:https://www.cnblogs.com/yanchenyu/p/10948973.html