浏览器缓存

web缓存的种类有很多种,比如数据库缓存、CDN缓存、代理服务器缓存、浏览器缓存等,这里我们主要了解一下浏览器的缓存机制。

浏览器端的缓存规则

对于浏览器端的缓存来讲,这些规则是在HTTP协议头和HTML页面的Meta标签中定义的。他们分别从新鲜度和校验值两个维度来规定浏览器是否可以直接使用缓存中的副本,还是需要去源服务器获取更新的版本。

  • 新鲜度(过期机制):也就是缓存副本有效期。一个缓存副本必须满足以下条件,浏览器会认为它是有效的,足够新的:含有完整的过期时间控制头信息(HTTP协议报头),并且仍在有效期内;
    浏览器已经使用过这个缓存副本,并且在一个会话中已经检查过新鲜度;
    满足以上两个情况的一种,浏览器会直接从缓存中获取副本并渲染。

  • 校验值(验证机制):服务器返回资源的时候有时在控制头信息带上这个资源的实体标签Etag(Entity Tag),它可以用来作为浏览器再次请求过程的校验标识。如过发现校验标识不匹配,说明资源已经被修改或过期,浏览器需求重新获取资源内容。

图示:

两个概念

  • 强缓存:(Chrome下的现象是 200 OK (from disk cache) 或者 200 OK (from memory cache))
    用户发送的请求,直接从客户端缓存中获取,不发送请求到服务器,不与服务器发生交互行为。

  • 协商缓存:(也就是我们常见的304状态码)
    用户发送的请求,发送到服务器后,由服务器判定是否从缓存中获取资源。

  • 两者共同点:客户端获得的数据最后都是从客户端缓存中获得。

  • 两者的区别:从名字就可以看出,强缓存不与服务器交互,而协商缓存则需要与服务器交互。

对上诉步骤进行一些解说

步骤b:缓存是否过期

两个参数:expires 、Cache-Control

当response header中,Expires和Cache-Control同时存在时,Cache-Control优先级高于Expires

  • expires

Http1.0 中的标准,表明过期时间,注意此处的时间都是指的是服务器的时间。

存在的问题:服务器时间与客户端时间的不一致,就会导致缓存跟期待效果出现偏差。

  • Cache-Control

Http1.1 中的标准,可以看成是 expires 的补充。使用的是相对时间的概念。

Cache-Control的属性设置

参数 解析
max-age 设置缓存的最大的有效时间,单位为秒(s)。max-age会覆盖掉Expires。>0读取缓存,<=0向server 发送http 请求确认 ,该资源是否有修改,有的话返回200 ,无的话返回304.
s-maxage 只用于共享缓存,比如CDN缓存(s -> share)。与max-age的区别是:max-age用于普通缓存,而s-maxage用于代理缓存。如果存在s-maxage,则会覆盖max-age 和 Expires.
public 响应会被缓存,并且在多用户间共享。默认是public。
private 响应只作为私有的缓存,不能在用户间共享。如果要求HTTP认证,响应会自动设置为private
no-cache 指定不缓存响应,表明资源不进行缓存。但是设置了no-cache之后并不代表浏览器不缓存,而是在缓存前要向服务器确认资源是否被更改。因此有的时候只设置no-cache防止缓存还是不够保险,还可以加上private指令,将过期时间设为过去的时间。
no-store 绝对禁止缓存
must-revalidate 如果页面过期,则去服务器进行获取

图示:

所以判断缓存是否过期步骤是:

1) 查看是否有cache-control 的max-age / s-maxage , 如果有,则用服务器时间date值 + max-age/s-maxage 的秒数计算出新的过期时间,将当前时间与过期时间进行比较,判断是否过期

2)查看是否有cache-control 的max-age / s-maxage,则用expires 作为过期时间比较

图示:

步骤c:跟服务器协商是否使用缓存

到这一步的时候,浏览器会向服务器发送请求,同时如果上一次的缓存中有Last-modified 和 Etag 字段,
浏览器将在request header 中加入If-Modified-Since(对应于Last-modified), 和If-None-Match(对应于Etag)。

  • Last-modified: 表明请求的资源上次的修改时间。
  • If-Modified-Since:客户端保留的资源上次的修改时间。
  • Etag:资源的内容标识。(不唯一,通常为文件的md5或者一段hash值,只要保证写入和验证时的方法一致即可)
  • If-None-Match: 客户端保留的资源内容标识。

步骤d:协商缓存

在这个阶段,服务器一般会将Cache-control、expires 、last-modified、date、etag 等字段在response header 中返回,便于下次缓存。当然具体的场景,也是看服务器的约定规则设定。

缓存的不同来源

from disk cache

从磁盘中获取缓存资源,等待下次访问时不需要重新下载资源,而直接从磁盘中获取。它的直接操作对象为CurlCacheManager。

一般非脚本会存在内存当中,如css等

from memory cache

从内存中获取资源,等待下次访问时不需要重新下载资源,而直接从内存中获取。Webkit早已支持memoryCache。
目前Webkit资源分成两类,一类是主资源,比如HTML页面,或者下载项,一类是派生资源,比如HTML页面中内嵌的图片或者脚本链接,分别对应代码中两个类:MainResourceLoader和SubresourceLoader。虽然Webkit支持memoryCache,但是也只是针对派生资源,它对应的类为CachedResource,用于保存原始数据(比如CSS,JS等),以及解码过的图片数据。

一般脚本、字体、图片会存在内存当中。

区别

当退出进程时,内存中的数据会被清空,而磁盘的数据不会,所以,当下次再进入该进程时,该进程仍可以从diskCache中获得数据,而memoryCache则不行。

相似

diskCache与memoryCache相似之处就是也只能存储一些派生类资源文件。它的存储形式为一个index.dat文件,记录存储数据的url,然后再分别存储该url的response信息和content内容。Response信息最大作用就是用于判断服务器上该url的content内容是否被修改。

图:

用户行为的缓存变化

f5刷新(mac 即command + r)

没啥变化

强制刷新(command+shift+r)

在request中多了个属性:
都有Cache-Control: no-cache的标识。
这表明每次都需要服务器评估是否有效,不要理解为直接不使用缓存。
此外可以注意到request中没有可以匹配response中ETag的If-None-Match属性,
所以会重新加载。

304->200

看图很清晰:

扩展阅读

link1

link2