扼杀 304,Cache-Control: immutable

随着近些年社交网站的流行,愈来愈多的人学会了“刷”网页 ── 刷微博,刷朋友圈,刷新闻,刷秒杀页。这里的“刷”,就是刷新的意思,在浏览器里,你能够经过点击刷新按钮,或者用快捷键,或者移动端的下拉操做来进行刷新。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 更高。

相关文章
相关标签/搜索