浏览器缓存做为性能优化的重要一环,对于前端而言,重要性不言而喻。之前老是只知其一;不知其二的,因此此次好好整理总结了一下。
一、缓存机制
首先咱们来整体感知一下它的匹配流程,以下:css
- 浏览器发送请求前,根据请求头的expires和cache-control判断是否命中(包括是否过时)强缓存策略,若是命中,直接从缓存获取资源,并不会发送请求。若是没有命中,则进入下一步。
- 没有命中强缓存规则,浏览器会发送请求,根据请求头的last-modified和etag判断是否命中协商缓存,若是命中,直接从缓存获取资源。若是没有命中,则进入下一步。
- 若是前两步都没有命中,则直接从服务端获取资源。
二、强缓存
强缓存:不会向服务器发送请求,直接从缓存中读取资源。前端
2.1 强缓存原理
强制缓存就是向浏览器缓存查找该请求结果,并根据该结果的缓存规则来决定是否使用该缓存结果的过程,强制缓存的状况主要有三种(暂不分析协商缓存过程),以下:nginx
- 第一次请求,不存在缓存结果和缓存标识,直接向服务器发送请求
- 存在缓存标识和缓存结果,可是已经失效,强制缓存是啊比,则使用协商缓存(暂不分析)
- 存在该缓存结果和缓存标识,且该结果还没有失效,强制缓存生效,直接返回该结果
那么强制缓存的缓存规则是什么?
当浏览器向服务器发起请求时,服务器会将缓存规则放入HTTP响应报文的HTTP头中和请求结果一块儿返回给浏览器,控制强制缓存的字段分别是Expires
和Cache-Control
,其中Cache-Control
优先级比Expires
高。git
2.1.一、 Expires
缓存过时时间,用来指定资源到期的时间,是服务器端的具体的时间点。也就是说,Expires=max-age + 请求时间
,须要和Last-modified
结合使用。Expires
是Web服务器响应消息头字段,在响应http请求时告诉浏览器在过时时间前浏览器能够直接从浏览器缓存取数据,而无需再次请求。github
Expires 是 HTTP/1 的产物,受限于本地时间,若是修改了本地时间,可能会形成缓存失效。
2.1.二、 Cache-Control
在HTTP/1.1中,Cache-Control是最重要的规则,主要用于控制网页缓存,主要取值为:segmentfault
- public:全部内容都将被缓存(客户端和代理服务器均可缓存)
- private:全部内容只有客户端能够缓存,
Cache-Control
的默认取值 - no-cache:客户端缓存内容,可是是否使用缓存则须要通过协商缓存来验证决定
- no-store:全部内容都不会被缓存,即不使用强制缓存,也不使用协商缓存
- max-age=xxx (xxx is numeric):缓存内容将在xxx秒后失效
须要注意的是,no-cache
这个名字有一点误导。设置了no-cache
以后,并非说浏览器就再也不缓存数据,只是浏览器在使用缓存数据时,须要先确认一下数据是否还跟服务器保持一致,也就是协商缓存。而no-store
才表示不会被缓存,即不使用强制缓存,也不使用协商缓存
2.1.三、设置
强缓存须要服务端设置expires
和cache-control
。nginx
代码参考,设置了一年的缓存时间:浏览器
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
。缓存
2.二、from disk cache和from memory cache
细心地同窗在开发的时候应该注意到了Chrome的网络请求的Size会出现三种状况from disk cache(磁盘缓存)
、from memory cache(内存缓存)
、以及资源大小数值。性能优化
状态 | 类型 | 说明 |
---|---|---|
200 | form memory cache | 不请求网络资源,资源在内存当中,通常脚本、字体、图片会存在内存当中 |
200 | form disk ceche | 不请求网络资源,在磁盘当中,通常非脚本会存在内存当中,如css等 |
200 | 资源大小数值 | 从服务器下载最新资源 |
304 | 报文大小 | 请求服务端发现资源没有更新,使用本地资源 |
浏览器读取缓存的顺序为memory –> disk。
以访问https://github.com/xiangxingchen/blog
为例
咱们第一次访问时https://github.com/xiangxingchen/blog
关闭标签页,再此打开https://github.com/xiangxingchen/blog
时
F5刷新时服务器
简单的对比一下
三、协商缓存
协商缓存就是强制缓存失效后,浏览器携带缓存标识向服务器发起请求,由服务器根据缓存标识决定是否使用缓存的过程,主要有如下两种状况:
- 协商缓存生效,返回304和Not Modified
- 协商缓存失效,返回200和请求结果
3.一、Last-Modified和If-Modified-Since
- 浏览器首先发送一个请求,让服务端在
response header
中返回请求的资源上次更新时间,就是last-modified
,浏览器会缓存下这个时间。 - 而后浏览器再下次请求中,
request header
中带上if-modified-since
:[保存的last-modified的值]
。根据浏览器发送的修改时间和服务端的修改时间进行比对,一致的话表明资源没有改变,服务端返回正文为空的响应,让浏览器中缓存中读取资源,这就大大减少了请求的消耗。
因为last-modified依赖的是保存的绝对时间,仍是会出现偏差的状况:
- 保存的时间是以秒为单位的,1秒内屡次修改是没法捕捉到的;
- 各机器读取到的时间不一致,就有出现偏差的可能性。为了改善这个问题,提出了使用etag。
3.二、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
四、用户行为对浏览器缓存的影响
- 打开网页,地址栏输入地址: 查找
disk cache
中是否有匹配。若有则使用;如没有则发送网络请求。 - 普通刷新 (F5):由于 TAB 并无关闭,所以
memory cache
是可用的,会被优先使用(若是匹配的话)。其次才是disk cache
。 - 强制刷新 (Ctrl + F5):浏览器不使用缓存,所以发送的请求头部均带有
Cache-control:no-cache
(为了兼容,还带了Pragma:no-cache
),服务器直接返回 200 和最新内容。