原文连接javascript
我的文章汇总在blogcss
缓存是一个很是重要一样也很是复杂的浏览器特性html
在这篇文章中,咱们将解释浏览器是如何利用缓存来使加载页面更快,哪些因素决定了缓存的周期,在必要的时候如何去避开缓存。html5
全部的浏览器都会尝试去缓存静态资源的本地副本,以此去下降页面的加载时间以及体积最小的网络传输java
不论服务是在相同的网络环境下仍是在世界上其余的网络环境下,从本地缓存中取资源必定会比经过网络请求的方式要快git
浏览器针对此站点没有任何的缓存文件,因此浏览器会向站点服务去请求全部所需的资源github
下面是一张首次访问维基百科首页的资源下载完以后的截图,底部状态栏显示出有265kb的数据传输到了浏览器中web
浏览器会去请求站点服务器取到html页面,而后会查看是否有对应静态资源的缓存(js, css, images)chrome
当咱们从新刷新维基百科的页面时,就能看出由于缓存的缘由与以前的请求情况不一样的地方浏览器
此时数据的传输量已经降到了928bytes,至关于首页访问页面时的0.3%,Size这一列就显示出了咱们的大多数的资源都来自于缓存
Chrome即会在memory cache中去拉取内容,也会在disk cache中去拉取内容,由于在case1和case2中,咱们尚未关闭浏览器,因此数据依然会存储在memory cache中
在chrome中,咱们能够在地址栏中输入chrome://cache去查看缓存的内容,对于每个已经缓存的文件,这里都将会显示一个页面连接,页面连接的内容包含一个更加详细的视图说明。
浏览器先去检查服务器所生成的http响应头信息,通常用于缓存相关的头信息有4个:
ETag(Entity Tag)是一个用于缓存校验token的字符串,它一般以文件的哈希值来表示
服务器能够添加ETag到它的响应里,浏览器接收到这个响应,那在将来的请求中(在文件过时以后),浏览器就能够根据这个字段去判断缓存中是否保留着一份过时的副本
若是经过对比hash值是相同的,那么就说明这个资源没有变化,服务器就会返回一个304状态码(Not Modified),浏览器就知道当前缓存的副本是安全的
注意:只有当缓存中的文件过时了,ETag才会被用在请求中
Cache-Control头拥有许多指令,利用这些指令咱们能够设置缓存的行为,过时时间,验证等,同时这些也能够组合起来一块儿进行设置。
Cache-Control: public
复制代码
public意味着资源能够被任意缓存(浏览器,CDN等)
Cache-Control: private
复制代码
private意味着资源只能被浏览器缓存
Cache-Control: no-store
复制代码
no-store意味着让浏览器老是去请求服务器以获取资源
Cache-Control: no-cache
复制代码
no-cache有一点误导性,它并非说“不要缓存”
这是在告诉浏览器去缓存这个文件,但在和服务器确认最新版本以前不要去使用它。这个验证的过程是经过ETag来完成的
这个行为通常会用在html文件中,由于浏览器总会去检查最新的html文件标识,因此这一点是讲得通的
Cache-Control: max-age=60
复制代码
这个指令指定了资源应该被缓存多少秒,因此max-age=60就意味着资源应该被缓存一分钟,RFC 2616推荐这里的最大值不要超过一年(max-age=31536000)
Cache-Control: s-max-age=60
复制代码
这个指令仅仅是被用在中间缓存(好比CDN)
Cache-Control: must-revalidate
复制代码
这个指令告诉缓存在使用它以前必须去验证资源的过时状态,若是已通过期就不该该被使用
Expires头部来源于http1.0版本,可是在当今许多站点中依然保留着
这个头部字段指定了一个日期,超过这个日期就表明资源是无效的
Expires: Wed, 25 Jul 2018 21:00:00 GMT
复制代码
注意:若是已经指定了Cache-Control中的max-age指令,那浏览器就会忽略expires
Last-Modified头部也是来自http1.0版本
Last-Modified: Mon, 12 Dec 2016 14:45:00 GMT
复制代码
这个字段包含了资源最后修改的日期和时间
在HTML5版本以前,在html中使用元标签(meta tag)制定cache-control是一个有效的方式
<meta http-equiv="Cache-control" content="no-cache">
复制代码
但在html5中已经不推荐这么作了,为何?由于只有浏览器能够识别这个标签,而中间缓存(CDN)是识别不了的。
因此最好是都经过http头的方式去发送缓存指令
让咱们来看一个简单的http响应
Accept-Ranges: bytes
Cache-Control: max-age=3600
Connection: Keep-Alive
Content-Length: 4361
Content-Type: image/png
Date: Tue, 25 Jul 2017 17:26:16 GMT
ETag: "1109-554221c5c8540"
Expires: Tue, 25 Jul 2017 18:26:16 GMT
Keep-Alive: timeout=5, max=93
Last-Modified: Wed, 12 Jul 2017 17:26:05 GMT
Server: Apache
复制代码
因此咱们已经意识到缓存是个好东西,咱们应该积极利用它
可是咱们但愿的是,不须要让用户每次都去刷新(Ctrl + F5)或者清空缓存才能看到咱们页面的最新内容
这类缓存问题常常困扰者开发者以及用户,用户可能会看到一个错乱的页面或者是一个行为怪异的按钮,由于他们当前使用的已是过时的静态资源文件
下面这张截图描述了一个银行网站的用户与Chase Support之间的交流,能够看到是有关登录表单出了问题
该用户颇有可能还在使用老的js文件,这就是致使点击登录按钮是表单重置操做而不是表单提交操做
让咱们来探索过时文件影响咱们的另一种状况。
假设咱们在一个叫作app.min.js的文件中修复了一个bug,而且把它推送到了生产环境
在HTML中,该脚本是这个样子
<script src="assets/js/app.min.js">
复制代码
咱们的web服务器给这个js文件设置了max-age为1周(604800秒)的过时时间
Cache-Control: private, max-age=604800
复制代码
在更新完该js文件以后,一些用户仍在反馈说那个bug依然存在。 那这里到底发生了什么呢?
在下一个章节中,咱们将会利用一个叫作"cache busting"的技术来解决这些问题和状况
Cache busting会使一个资源文件失效,强制浏览器去服务器端从新获取数据。
咱们能够经过改变文件名来命令浏览器去避开缓存,对于浏览器来讲,这是一份彻底新的资源,因此浏览器会去服务端请求最新的数据
Cache busting一样容许咱们设置一个比较长的max-age值针对频繁改动的资源。Google推荐max-age被设为1年(source)
咱们能够给文件名添加一个版本号
assets/js/app-v2.min.js
复制代码
咱们能够基于文件内容添加一个指纹值
assets/js/app-d41d8cd98f00b204e9800998ecf8427e.min.js
复制代码
咱们能够在文件名的末尾拼接一个查询参数
assets/js/app.min.js?version=2
复制代码
拼接查询参数的方式在和代理服务器交互时有明显的错误(known issues),因此这种方式通常不推荐使用
打开web开发者工具,在chrome中,这个信息会显示在network面板中的Size列
使用下面的响应头
Cache-Control: no-cache, no-store, must-revalidate
复制代码
从chrome 66版本开始,chrome已经删除了chrome://cache,缘由能够参考reason1, reason2