缓存直观观察
浏览器开发面板的 Network 一栏,在加载网络资源的时候,size一列会有几种不同的情况:
from memory cache:表明直接从内存中加载,推测近期可能访问过资源(如刷新页面,此时就是从内存中取)from disk cache:表明从硬盘中加载缓存,比如我重启浏览器了,但硬盘中的缓存仍然有效(此时内存中的缓存已经丢了),就从硬盘中读取缓存资源size(数值):此时看请求是200还是304,200表明从服务器下载的资源,大小即资源大小,如果是304表明也发请求问过服务器了,但得知资源没有更新,可以使用缓存,此时的大小是请求报文大小

强缓存与协商缓存
浏览器在与服务器交互的过程中,通过缓存来提高交互效率,避免不必要的资源开销,其中缓存又分为强缓存和协商缓存两种,更加直白地说,强缓存就是浏览器自己根据已有信息校验资源是否过期,协商缓存就是浏览器自己判断不了,需要询问服务器是否过期。通常浏览器缓存的基本过程如下
浏览器在加载资源时,根据请求头的
expires和cache-control来检查是否可以使用缓存,如果浏览器可以根据这俩信息判断可用缓存,则直接从缓存读取资源,不会发请求到服务器,这个缓存过程就叫强缓存。如果没有命中强缓存,浏览器无法判断是否能用缓存,就要请求服务器,服务器通过响应中携带
last-modified和etag来告知浏览器资源的新鲜度信息,而浏览器发起协商缓存时,请求中通过if-modified-since和if-none-match来携带之前服务器给的新鲜度信息,让服务器判断资源是否过期,如果仍然没有过期,服务器会直接用304Code返回这个请求告知浏览器可以使用缓存,浏览器看到304就明白服务器的意思,直接从缓存中读取资源如果服务器发现浏览器持有的资源缓存已经不是最新的了(例如last-modify后又更新了),服务器会加载最新资源返回这个请求
强缓存中的 expires 和 Cache-Control
Expires
是http/1.0提出的一个表示资源过期时间的header,是一个GMTString表示的绝对时间,由服务器返回,即这个时间之前客户端都可以直接使用缓存
Expires: Wed, 11 May 2018 07:20:00 GMT
Cache-Control
HTTP/1.1提出,指令里用max-age实现Expires功能时,表示的是相对时间
Cache-Control: public,max-age=315360000
优先级高于 Expires,多个Cache-Control指令可以复合到一条
常用的指令有:
- max-age=
<seconds>,表示浏览器从拿到资源起,多久以后过期 - public / private / no-cache / no-store 这类属于可缓存性的指令
public / private 分别标明资源可以被请求链路中任何一个节点缓存以及只能被浏览器自己缓存
no-cache 并不像它名称表达的那样不允许缓存,而是允许缓存,但一定要协商才能确定是否可用
no-store 是真正意义上的禁用缓存,它要求浏览器不存储资源缓存
关于协商缓存
协商缓存提供了两种维度的资源新鲜度度量手段,对应到请求头上就是:Last-Modified 和 ETag
Last-Modified 是服务器下发资源的时候,告知客户端这个资源的最近一次改动时间的,客户端下次需要协商缓存的时候,用 Last-Modified-Since 带上这个值,服务器会拿去和资源的最新时间做比较,如果二者相同,说明资源仍然没有改变;
由此可见,使用Last-Modified进行缓存控制的精度是1秒,如果资源在1秒内发生多次改变,这个头部就无法感知变更
Last-Modified如何计算的: 在Nginx中,静态资源使用文件在文件系统的修改时间作为 Last-Modified
ETag 则是更加精细的变化控制,这个值由服务器通过某种算法对资源计算产生,只要内容改变,这个值就随之改变,故服务器在第一次资源下发的时候会将文件的Etag发给客户端,客户端在下次需要协商缓存的时候,带上Etag,如果服务器发现这个资源”签名”相同的话,就认为资源是没有改变的,304回之
ETag如何计算的: Etag在Nginx中,由 {Last-Modified时间的16进制表示}-{Content-Length的16进制表示}组成
如
5e7b7ddf-3dfe, 用16进制转10进制计算器可得1585151455-15870,这个Etag相应的Last-Modified时间就是 “Wed, 25 Mar 2020 15:50:55 GMT”, 且 Content-Length 是15870
后记
可以感受得到,无缓存、协商缓存和强缓存是一组递进关系
无缓存 服务器压力最大,无论多少次请求过来,都得老老实实回传资源
协商缓存 次之,浏览器不确定能不能用缓存还能发个消息问问服务器,如果服务器发现浏览器持有的内容没有过期,就可以只响应个304,不用传数据,偷了个大懒
强缓存 服务器0压力,浏览器自己看着时间玩儿去,压根儿就不要让服务器知道😁
再注:POST请求