浏览器缓存一共分为以下几块的知识点:
cache-control 属性:
max-age: 表示强制读取浏览器内部的缓存的时间段
s-maxage: 也是表示强制读取缓存时间,但是它是读取 浏览器 与 服务器之间的一些代理服务器上的缓存,例如 CDN。就拿CDN 举例:如果没有超过这个时间,浏览器会带上 last-modify-since 请求CDN 上的缓存文件,然后 CDN 通过对该文件的 last-modify 作对比,如果一致那么直接返回缓存文件,而如果超过了 s-maxage 的时间,那么CDN 会带上浏览器缓存的 last-modify-since 的值请求源服务器。如果服务器的last-modify 与 last-modify-since 的值一致那么还是会返回 CDN 上的资源给浏览器,否则由源服务器更新 CDN 上面的资源再返回给浏览器。
因此有时候尽管 s-maxage 已经过了期但是状态码仍然会是304,这是因为源服务器文件并没有更新继续读取了 CDN 上面的资源。
public: 表示允许被中间代理服务器缓存
private: 表示允许浏览器自身缓存
no-cache: 表示浏览器不会像设置了 max-age 或 s-max-age 那样直接不询问服务器读取缓存的资源,而是会发送一个请求询问服务器这个资源有没有被修改,如果有请求这个资源并缓存,否则直接读缓存。
no-store: 表示不存缓存,每一次都直接读服务器
s-maxage 的优先级比 max-age 高
expires: 和 cache-control 的 max-age 属性一样也是控制缓存的读取时间,不过这个是 http 1.0 提出的标准,到了 http 1.1 为了更加规范的管理头部 新增了 cache-control。所以当 max-age 和 expires 同时存在的情况下 max-age 的优先级比 expires 更高。
last-modify & last-modify-since
last-modify: 这个头部属性是存在响应头中的,表示服务器对这个请求资源最后的修改时间的标识,并且会一起缓存到浏览器中
last-modify-since: 这个头部属性会存在请求头中,每次请求这个资源时都会根据上一次通过服务器的响应缓存存好了的 last-modify 的值一并发送给服务器,服务器通过对这个请求资源的修改时间做对比如果最后修改时间不匹配则重新发送一份新的资源给客户端,否则继续读缓存 此时响应的code 是 304。
但是 last-modify 有一些缺点:例如获取时间的不精准导致发生误差 或者是 文件的修改时间变了但是内容却没变等等...
所以 ETag 应运而生
ETag && if-none-match
ETag: 存放在响应头部的属性,返回一个hash 值,表示文件当前的修改状态并且存入客户端的缓存中
if-none-match: 存放在请求头的属性,与服务器的作比对,如果发现不一样,则将服务器的文件更新到缓存中。
ETag 的改变是只有检测到文件内容的改变才会发生改变的 所以精准度比 last-modify 要更高,而且 ETag 比 last-modify 的优先级更高
整个缓存策略的分级如下所示:
流程大概如下:
如果有 s-maxage 那么会像上面所介绍 s-maxage 那样做一些对比工作
如果没有 s-maxage,那么判断 expires 或者 cache-control 里面的 max-age 有没有过期,没有的话浏览器根本不去请求服务器而是直接访问本地或中间服务的缓存。
而如果 expires 或者 max-age 过期,那么每次请求都会对比 ETag 的值是否相同,如果相同则读取缓存,否则请求服务器更新资源。
如果没有 ETag 这个属性,就会拿 last-modify 这个值去判断,如果相同读取缓存,否则请求服务器更新缓存资源。
需要说明的是,通过 ETag 或 last-modify 读取缓存的时候 浏览器的状态码会显示304,而请求服务器更新缓存的时候会是 200
当以上的情况都不存在的时候,浏览器直接请求服务器资源
总的来说缓存策略的优先级分别如下:
s-max-age > max-age > expires > ETag > last-modify > 直接请求服务器