随着近些年社交网站的流行,愈来愈多的人学会了“刷”网页 ── 刷微博,刷朋友圈,刷新闻,刷秒杀页。这里的“刷”,就是刷新的意思,在浏览器里,你能够经过点击刷新按钮,或者用快捷键,或者移动端的下拉操做来进行刷新。html
但普通网民不知道的是,经过刷新操做致使的页面加载和经过其余操做(好比点击页面连接,地址栏输入网址并回车,点击收藏夹网址等)致使的页面加载有一点不一样,那就是刷新操做会给该页面的请求自己以及页面里所引用的资源们(JS,CSS,图片等)的请求加上 If-Modified-Since 和 If-None-Match 请求头(若是已经有缓存且有 Last-Modified/ETag 响应头的话),服务器会根据这两个请求头判断该资源有没有更新过,若是没有,就返回不带响应体的 304 响应,告诉浏览器:“用缓存吧”,若是更新过了,则把更新后的资源放在响应体里返回 200 响应。git
咱们把上面说的这种带有 If-Modified-Since 或 If-None-Match 请求头的 HTTP 请求叫作条件请求,除了刷新操做,条件请求还会发生在缓存过时的时候,也就是已缓存时长大于 Cache-Control 响应头中的 max-age 字段指定的秒数的时候。github
条件请求是设计用来更新资源的,但实际状况是,在现现在的网站开发中,尤为是大型网站,会依赖适当的过时时长或者让用户手动刷新来更新页面吗?好比把缓存时长设置成一小时,新版页面上线了,用户都看不到效果,老板过来问:“这怎么回事啊,不是上线了吗”,开发回答:“要等一小时缓存过时啊,你也能够刷新一下就看到效果了~”。显然不可能这样,对于那些有更新需求的静态资源,常见的是 JS、CSS,咱们都会在它的 URL 里加上点东西,时间戳、版本号、哈希值等,能够放在 URL 的路径里,也能够放在查询参数里,由于只要 URL 变了,浏览器就认为是不一样的资源,就会从新下载;还有一些静态资源是彻底没有更新需求的,好比你在微博上传的那些图片,同一个 URL 对应的资源是永远不会变的。web
上面说的这两种状况,实际上是一种,就是它们永远没有更新的需求,它们是不可变的,是 immutable 的,304 用在它们身上彻底没有意义,全是浪费。虽然每一个 304 请求的往返体积只有 1k 左右,但架不住多啊。并且就算只有一个字节,也会致使页面展示变慢,读本地文件和读网络资源仍是有本质区别的。浏览器
Facebook 在一年前意识到了这个问题,它的工程师给制定 HTTP 标准的 IETF 工做组发了封邮件,里面说到,Facebook 使用版本号来更新静态资源,还给静态资源设置了几乎不可能过时的缓存时长,但发现仍然有 20% 的请求是无心义的条件请求(必然 304),这给服务器性能带来很大伤害,他们研究发现是由于 Facebook 页面 pv 有 2% 来自用户的刷新操做,他们但愿 HTTP 协议能给 Cache-Control 响应头增长一个属性字段代表该资源永不过时,浏览器就不必再为这些资源发送条件请求了。缓存
今年四月份,Mozilla 的人觉的 Facebook 提的这个建议很好,因而他们在 Firefox 49 里实现了 Cache-Control: immutable。immutable 的推荐用法是和那些超大的 max-age 配合使用,好比 1年:Cache-Control: max-age=31536000, immutable,甚至 10年, 但一般状况下,1 年就够了,由于:1. 对于单个缓存来讲,它在某个浏览器里存活的时长不可能超过一年,浏览器的缓存空间都有上限,Firefox 256M,Chrome 320M,旧的缓存会时不时被清掉。2. 一个用户不大可能一年后还来同一个页面,且那个页面还没改版。对缓存时长来讲,1 年就表明永远了。服务器
但这只是推荐作法,immutable 并非真的只能应用在那些永不过时的资源上,也能够配合较小的 max-age 来使用,好比一些我的博客,或者一些不太讲究及时更新的站点,能够设置成 Cache-Control: max-age=3600, immutable,代表该资源能存活一小时,在一小时以内,即使用户刷新也不要发送条件请求,在过时以后,浏览器会发送不带一个不带 If-Modified-Since 和 If-None-Match 的请求来更新资源,这里须要注意,一旦被标志成 immutable,则这个资源不可能返回 304 响应了,只有 200。网络
目前 Firefox 的实现里,只对 HTTPS 资源开放 immutable 属性的支持,我经过 Fiddler 在本地篡改了淘宝搜索页面 https://s.taobao.com/search?q=连衣裙 里全部资源的 Cache-Control 响应头,在原值尾部加上 “, immutable”。篡改以前,假如我刷新一下此页面,会致使数十个 304 响应:app
篡改以后的刷新效果:frontend
注意那些带有 cached 字样的 200 请求,那些请求实际上根本不是真正的请求,只是一次本地读取文件的操做。
目前 Facebook 尚未反馈 immutable 的测试数据,毕竟 Firefox 49 还不是正式版,之后应该会有的。不过考虑到如今 Firefox 的市场占有率,也许 Chrome 实现以后才会获得更多人的关注, Chrome 也表示了有意愿去实现。不过我在 GitHub 搜了一下,却是发现 W3C 的网站和 Firefox 附加组件网站准备实现。
immutable 只有在你的网站被频繁刷新的状况下才有较大的意义。还有虽然它是向后兼容的,但可能一些 CDN 服务器在识别 Cache-Control 时因不认识这个属性,致使最终返回给浏览器的响应丢失了 immutable,推特上有反应 Akamai 就这么干了。
少数人知道的强制刷新功能(Ctrl+F5/Shift+Command+R)以及开发者工具的跳过缓存功能优先级应比 immutable 更高。