浏览器强缓存和协商缓存

2,083 阅读5分钟

缓存机制

  1. 浏览器发送请求前,根据请求头的expires和cache-control判断是否命中强缓存策略,如果命中,直接从缓存获取资源,并不会发送请求。如果没有命中,进入下一步。
  2. 没有命中强缓存规则,浏览器会发送请求,根据请求头的last-modified和etag判断是否命中协商缓存,如果命中,直接从缓存中获取资源。如果没有命中,进入下一步。
  3. 如果前两步都没有命中,则直接从服务器中获取资源。

1. 强缓存

不会向服务器发送请求,直接从缓存中读取资源

三种情况:

  1. 第一次请求,不存在缓存结果和缓存标识,直接向服务器发送请求
  2. 存在缓存标识和缓存结果,但是缓存结果已经失效,则使用协商缓存
  3. 存在该缓存结果和缓存标识,且该结果尚未失效,强制缓存生效,直接返回该结果

当浏览器向服务器发起请求时,服务器会将缓存规则放入HTTP响应头中返回给浏览器,控制强缓存的字段分别是Expires和Cache-Control,其中Cache-Control优先级比Expires高。

Expires

Expires用来指定资源到期时间,Expires是服务器响应信息头字段,在响应http请求时告诉浏览器在过期时间之前浏览器可以直接从浏览器缓存中,而无需再次请求。

Cache-Control

Cache-Control是最重要的规则,主要用于控制网页缓存,主要取值为:

  • public:所有内容都将被缓存(客户端和代理服务器都可缓存)
  • private:所有内容只有客户端可以缓存,Cache-Control的默认取值
  • no-cache:客户端缓存内容,但是是否使用缓存则需要经过协商缓存来验证决定
  • no-store:所有内容都不会被缓存,即不使用强制缓存,也不使用协商缓存
  • max-age=xxx (xxx is numeric):缓存内容将在xxx秒后失效

需要注意的是,no-cache这个名字有一点误导。设置了no-cache之后,并不是说浏览器就不再缓存数据,只是浏览器在使用缓存数据时,需要先确认一下数据是否还跟服务器保持一致,也就是协商缓存。而no-store才表示不会被缓存,即不使用强制缓存,也不使用协商缓存

nginx设置

强缓存需要服务器设置Expires和Cache-Control

// 设置一年的缓存时间

location ~ .*\.(ico|svg|ttf|eot|woff)(.*) {
  proxy_cache               pnc;
  proxy_cache_valid         200 304 1y;
  proxy_cache_valid         any 1m;
  proxy_cache_lock          on;
  proxy_cache_lock_timeout  5s;
  proxy_cache_use_stale     updating error timeout invalid_header http_500 http_502;
  expires                   1y;
}

from disk cache 和 from memory cache

网络请求的size会出现三种情况

  1. from memory cache (内存缓存)
  2. from disk cache (磁盘缓存)
  3. 100KB (资源数值大小)
  • 100KB 状态码为200, 直接从服务器下载最新资源
  • from memory cache 不请求网络资源,资源在内存当中,一般脚本,字体,图片会存放在内存当中
  • from disk cache 不请求网络资源,在磁盘当中,一般非脚本会存在内存当中,如css

http状态码为304 表示报文大小,请求服务端发现资源没有更新,使用本地资源

2. 协商缓存

协商缓存就是强缓存失效后,浏览器携带缓存标识向服务器发起请求,由服务器根据缓存标识决定是否使用缓存的过程。

  • 协商缓存生效,返回304 和 Not Modified

  • 协商缓存失效,返回200 和 请求结果

2.1 Last-Modified和If-Modified-Since

  1. 浏览器首先发送一个请求,让服务端在response header中返回请求的资源上次更新时间,就是last-modified,浏览器会缓存下这个时间。
  2. 然后浏览器再下次请求中,request header中带上if-modified-since:[保存的last-modified的值]。根据浏览器发送的修改时间和服务端的修改时间进行比对,一致的话代表资源没有改变,服务端返回正文为空的响应,让浏览器中缓存中读取资源,这就大大减小了请求的消耗。

2.2 ETag和If-None-Match

etag是http协议提供的若干机制中的一种Web缓存验证机制,并且允许客户端进行缓存协商。生成etag常用的方法包括对资源内容使用抗碰撞散列函数,使用最近修改的时间戳的哈希值,甚至只是一个版本号。 和last-modified一样

  • 浏览器会先发送一个请求得到etag的值,然后再下一次请求在request header中带上if-none-match:[保存的etag的值]。
  • 通过发送的etag的值和服务端重新生成的etag的值进行比对,如果一致代表资源没有改变,服务端返回正文为空的响应,告诉浏览器从缓存中读取资源。

etag能够解决last-modified的一些缺点,但是etag每次服务端生成都需要进行读写操作,而last-modified只需要读取操作,从这方面来看,etag的消耗是更大的。

二者对比

  • 精确度上:Etag要优于Last-Modified。
  • 优先级上:服务器校验优先考虑Etag。
  • 性能上:Etag要逊于Last-Modified

3. 用户行为对浏览器缓存的影响

  1. 打开网页,地址栏输入地址: 查找 disk cache 中是否有匹配。如有则使用;如没有则发送网络请求。
  2. 普通刷新 (F5):因为 TAB 并没有关闭,因此 memory cache 是可用的,会被优先使用(如果匹配的话)。其次才是 disk cache。
  3. 强制刷新 (Ctrl + F5):浏览器不使用缓存,因此发送的请求头部均带有 Cache-control:no-cache(为了兼容,还带了 Pragma:no-cache),服务器直接返回 200 和最新内容。

原文地址