在了解了整个缓存策略或者说缓存读取流程后,我们还需要了解一个东西,那就是用户对浏览器的不同操作,会触发不同的缓存读取策略。
对应主要有 3 种不同的浏览器行为:
-
打开网页,地址栏输入地址:查找 Disk Cache 中是否有匹配。如有则使用;如没有则发送网络请求。
-
普通刷新 (F5):因为 TAB 并没有关闭,因此 Memory Cache 是可用的,会被优先使用(如果匹配的话)。其次才是 Disk Cache。
-
强制刷新 ( Ctrl + F5 ):浏览器不使用缓存,因此发送的请求头部均带有 Cache-control: no-cache(为了兼容,还带了 Pragma: no-cache )。服务器直接返回 200 和最新内容。
ServiceWorker需要手动设置,其他的都是浏览器的默认行为
按照浏览器缓存的位置来分 分为四种由上到下进行查找 Service Worker 必须使用https协议,因为Service Worker涉及到请求拦截,所以必须用https协议来保障安全 先要注册Service Worker,他就像是一个代理服务器(代理浏览器请求) 流程: 浏览器请求资源会经过SW(Service Worker)如果SW中有对应资源,就会直接返回SW中的资源,如果没有就会发送请求给服务器,返回对应资源会保存在SW中,下次请求的时候就会直接返回资源 可以用来做离线网页,就算没有网络了,之前的数据会缓存在SW中,所以一些数据就还是能显示
Memory Cache 内存缓存 Memory Cache是缓存在内存中的,这样读取的速度会比较快。 作用是:第一次打开页面会请求数据,然后会把数据放在内存中,如果页面刷新了就不会再次发送请求,就直接会用内存中的缓存。 这种缓存会随着进程的释放而释放,当页面关闭的时候也就没了 Memory Cache机制保证了一个页面中如果有两个相同的请求,就只会请求一次
Disk Cache 硬盘缓存 Disk Cache就是缓存在硬盘中的数据,缺点是:读取时间会慢一些,优点是:可以存的数据量比较大,存储的时效性比较长 浏览器会自动根据http中的字段判断哪些资源需要缓存,哪些资源可以不请求直接使用,哪些资源已经过期了需要重新请求 并且在跨站点的情况下,相同地址的资源一旦被硬盘缓存下来,就不会再次去请求数据 凡是持久性存储都会面临容量增长的问题,浏览器会自动清理那些被浏览器判断为“最老的”和“最可能过时”的资源,不同的浏览器对这块判断的算法会有不同
Push Cache 推送缓存 是http/2中新增的内容,只有上面三种缓存都没有命中的时候,它才会被使用。 它只在会话窗口(session)中存在,一旦会话结束就会被释放。并且缓存时间也比较短,在Chrome中大约只有5分钟左右的时间,同时它也并非严格执行http/2头中的缓存指令。
缓存类型来分 按照缓存类型来分,可以分为强制缓存和协商缓存。需要注意的是无论是强制缓存还是协商缓存他们都是Disk Cache(硬盘缓存)或者叫做HTTP Cache里面的一种 强制缓存 强制缓存指,当客户端请求后,会先访问缓存数据库查看缓存是否存在,如果存在就直接返回;如果不存在则请求真实服务器,响应后写入缓存数据库 强制缓存可以直接减少请求数,是提升最大的缓存策略。如果考虑使用缓存来优化网页性能的话,强制缓存应该是首先被考虑的。 可以造成强制缓存的字段是Cache-control和Expires
Expires
这是 HTTP 1.0 的字段,表示缓存到期时间,是一个绝对的时间 (当前时间+缓存时间),如:
Expires: Thu, 10 Nov 2017 08:45:11 GMT
在响应消息头中,设置这个字段之后,就可以告诉浏览器,在未过期之前不需要再次请求。 但是,这个字段设置时有两个缺点: 由于是绝对时间,用户可能会将客户端本地的时间进行修改,而导致浏览器判断缓存失效,重新请求该资源。此外,即使不考虑自行修改的因素,时差或者误差等因素也可能造成客户端与服务端的时间不一致,致使缓存失效。
-
写法太复杂了。表示时间的字符串多个空格,少个字母,都会导致变为非法属性从而设置失效。
Cache-Control
在http/1.1中新增加了一个字段Cache-Control,该字段来表示资源缓存的最大有效时间,在该时间内,客户端不需要向服务端发送请求 这两者的区别就是前者是绝对时间,而后者是相对时间。如下:
Cache-control: max-age=2592000 //时间戳
下面列举一些 Cache-control 字段常用的值:(完整的列表可以查看 MDN)
-
max-age:即最大有效时间,在上面的例子中我们可以看到
-
must-revalidate:如果超过了 max-age 的时间,浏览器必须向服务器发送请求,验证资源是否还有效。
-
no-cache:虽然字面意思是“不要缓存”,但实际上还是要求客户端缓存内容的,只是是否使用这个内容由后续的协商缓存来决定。
-
no-store:真正意义上的“不要缓存”。所有内容都不走缓存,包括强制缓存和协商缓存。
-
public:所有的内容都可以被缓存(包括客户端和代理服务器, 如 CDN )
-
private:所有的内容只有客户端才可以缓存,代理服务器不能缓存。默认值。
这些值可以混合使用,例如 Cache-control:public, max-age=2592000。
协商缓存 当强缓存过期了之后,就需要用到协商缓存,由服务器决定缓存是否失效。 在流程上说,浏览器会请求缓存数据库,返回一个缓存标识,然后回发起请求,请求携带者这个缓存标识,如果服务器确认服务器这里的数据没有更新(缓存未失效),就会返回一个304,表示可以继续只用原来的那个强制缓存的内容,于是客户端就是继续使用缓存。如果数据已经失效了,服务器就会返回新的数据和缓存规则,再把规则写入到缓存数据库中,这是的状态码是200 协商缓存的请求数和没有缓存是一致的,因为请求会真实的到达服务器,只不过是返回一个304或者是真实返回数据的区别
对比缓存有 2 组字段(不是两个):
-
Last-Modified & If-Modified-Since(第一组)
-
Etag & If-None-Match(第二组)
Last-Modified & If-Modified-Since 服务器通过Last-modified字段告知客户端,资源最后一次被修改的时间,浏览器将这个值和内容一起记录在缓存数据库中,在下一次请求的时候浏览器会在自己的缓存中找出“不确定是否过期”的缓存,把上一次Last-Modified的值写入到请求头的If-Modified-Since字段中,然后服务器会将If-Modified-Since和Last-Modified-Since进行对比如果相同就会响应304,不相同就会返回状态码200,并返回新的数据 第一组缺陷: 如果资源更新的时候使秒一下的单位,那这个方法是不能用的,因为它的更新时间最小单位是秒 如果文件是通过服务器动态生成的,那更新的时间永远是生成的时间,这样客户端的时间永远都是不对的,尽管文件的内容可能没有改变,所以就起不到缓存的作用了,之后所以出现了第二组
Etag & If-None-Match
Etag & If-None-Match和Last-Modified & If-Modified-Since原理是一样的不过Etag存储的是哈希值(一般都是哈希值)然后传输哈希值进行对比 之后的流程和 Last-Modified 一致,只是 Last-Modified 字段和它所表示的更新时间改变成了 Etag 字段和它所表示的文件 hash,把 If-Modified-Since 变成了 If-None-Match。
两个的对比在精确度上Etag要优于Last-modified,因为Last-modified的最小单位是秒,如果在同一秒内数据进行了多次更改,用Last-modified就不会显示出更改