web性能优化之:no-cache与must-revalidate深入探究

引言

稍微了解HTTP协议的前端同学,相比对Cache-Control不会感到陌生,性能优化时经常都会跟它打交道。

常见的值有有private、public、no-store、no-cache、must-revalidate、max-age等。

各个取值所代表的含义,网上总结挺多的,这里就不打算再进行逐一介绍,感兴趣的可以一起探讨交流。

本文仅挑no-cache、must-revalidate 这两个进行值进行探究对比。在项目实践中,这两个值用的比较多,也比较容易搞混。

Cache-Control: no-cacheCache-Control: max-age=60, must-revalidate

传送门:RFC2616关于Cache-Control首部的介绍

no-cache、must-revalidate简介

  • no-cache: 告诉浏览器、缓存服务器,不管本地副本是否过期,使用资源副本前,一定要到源服务器进行副本有效性校验。
  • must-revalidate:告诉浏览器、缓存服务器,本地副本过期前,可以使用本地副本;本地副本一旦过期,必须去源服务器进行有效性校验。

上面的介绍涉及三个主体:浏览器、缓存服务器、源服务器。下面小节会简单进行介绍。

浏览器、缓存服务器、源服务器

  • 浏览器:资源请求直接发起方。
  • 源服务器:资源实际提供方。
  • 缓存服务器:在浏览器、源服务器之间架设的中间服务器,由它代替浏览器,向源服务器发起资源请求;

缓存服务器作用如下。缓存服务器不是必须的,浏览器可也可与源服务器直接通信。

加速资源访问速度,降低源服务器的负载。缓存服务器从源服务器获取资源,并返回给浏览器。此外,缓存服务器一般还会在本地保存资源的副本,当有相同的资源请求到来,缓存服务器可返回资源副本,以此提高资源访问速度。

对比测试场景、环境准备

对比测试场景

下文会通过以下两种场景的对比测试,来探究no-cache、must-revalidate的区别。

  • 浏览器 直接访问 源服务器。
  • 浏览器 通过 缓存服务器,间接访问 源服务器。

环境准备

  • 操作系统:OSX 10.11.4
  • 浏览器:Chrome 52.0.2743.116 (64-bit)、Firefox 49.0.2
  • 缓存服务器:Squid 3.6
  • 源服务器:Express 4.14.0

1、下载实验代码:可以访问github主页获取,也可通过git clone下载到本地。


  1. git clone https://github.com/chyingp/tech-experiment.git 
  2.  
  3. cd tech-experiment/2016.10.25-cache-control/ 
  4.  
  5. npm install  

2、安装Squid,步骤略,下载地址

3、可选:启动Squid,并将本地http代理设置为Squid的ip和端口。

备注:测试场景“通过缓存服务器,间接访问源服务器资源”时,才需要这一步。

4、可选:将本地代理设置为Charles的地址,然后将Charles的代理地址设置为squid的代理地址。(避免浏览器开发者工具对request header的修改,干扰实验结果)

场景一:浏览器->源服务器

首先,通过以下脚本启动本地服务器(源服务器)。


  1. cd connect-directly 
  2.  
  3. node server.js  

Cache-Control: no-cache

用例1:二次访问,源服务器 上 资源 未发生变化

访问地址为:http://127.0.0.1:3000/no-cache

步骤一:第一次访问,返回内容如下。可以看到,返回了Cache-Control: no-cache。


  1. HTTP/1.1 200 OK 
  2. X-Powered-By: Express 
  3. Cache-Control: no-cache 
  4. Content-Type: text/html; charset=utf-8 
  5. Content-Length: 11 
  6. ETag: W/"b-s0vwqaICscfrawwztfPIiA" 
  7. Date: Wed, 26 Oct 2016 07:46:28 GMT 
  8. Connection: keep-alive  

步骤二:第二次访问,返回内容如下。返回状态码为304 Not Modified,表示经过校验,源服务器上的资源没有变化,浏览器可以采用本地副本。


  1. HTTP/1.1 304 Not Modified 
  2. X-Powered-By: Express 
  3. Cache-Control: no-cache 
  4. ETag: W/"b-s0vwqaICscfrawwztfPIiA" 
  5. Date: Wed, 26 Oct 2016 07:47:31 GMT 
  6. Connection: keep-alive  

用例2:二次访问,源服务器 上 资源 发生变化

步骤一:访问地址为:http://127.0.0.1:3000/no-cach...

备注:change=1告诉源服务器,每次访问都返回不同内容

步骤一:第一次访问,内容如下,不赘述。


  1. HTTP/1.1 200 OK 
  2. X-Powered-By: Express 
  3. Cache-Control: no-cache 
  4. Content-Type: text/html; charset=utf-8 
  5. Content-Length: 11 
  6. ETag: W/"b-8n8r0vUN+mIIQCegzmqpuQ" 
  7. Date: Wed, 26 Oct 2016 07:48:01 GMT 
  8. Connection: keep-alive  

步骤二:第二次访问,返回内容如下。注意Etag变化了,表示源服务器资源已发生变化。于是状态码为200 OK,源服务器返回新版本的资源给浏览器。


  1. HTTP/1.1 200 OK 
  2. X-Powered-By: Express 
  3. Cache-Control: no-cache 
  4. Content-Type: text/html; charset=utf-8 
  5. Content-Length: 11 
  6. ETag: W/"b-0DK7Mx61dfZc1vIPJDSNSQ" 
  7. Date: Wed, 26 Oct 2016 07:48:38 GMT 
  8. Connection: keep-alive  

Cache-Control: must-revalidate

访问地址:http://127.0.0.1:3000/must-re...

可选参数说明:

  • max-age:源站返回的内容,max-age是多少(单位是s)。
  • change:源站返回的内容,是否变化,如果是1,则变化。

用例1:二次访问,浏览器缓存未过期

访问地址:http://127.0.0.1:3000/must-re...

备注:max-age=10表示,希望资源缓存10s

步骤一:第一次访问,返回内容如下。


  1. HTTP/1.1 200 OK 
  2. X-Powered-By: Express 
  3. Cache-Control: max-age=10, must-revalidate 
  4. Content-Type: text/html; charset=utf-8 
  5. Content-Length: 16 
  6. ETag: W/"10-dK948plT5cojN3y7Cy717w" 
  7. Date: Wed, 26 Oct 2016 08:06:16 GMT 
  8. Connection: keep-alive 

步骤二:第二次访问(在10s内),如下截图所示,浏览器直接从本地缓存里读取资源副本,并没有重新发起HTTP请求。

用例2:二次访问,浏览器缓存已过期,源服务器 资源未变化

步骤一:第一次访问略过。第二次访问如下截图所示(10s后),返回304 Not Modified。


  1. HTTP/1.1 304 Not Modified 
  2. X-Powered-By: Express 
  3. Cache-Control: max-age=10, must-revalidate 
  4. ETag: W/"10-dK948plT5cojN3y7Cy717w" 
  5. Date: Wed, 26 Oct 2016 08:09:22 GMT 
  6. Connection: keep-alive  

用例3:浏览器缓存已过期,源服务器 资源 已变化

访问地址:http://127.0.0.1:3000/must-re...

步骤一:第一次访问,截图如下。

步骤二:第二次访问(10s后),返回截图如下,可以看到返回了200。

 

场景2:浏览器->缓存服务器->源服务器

从上面的对比实验已经知道,在不经过缓存服务器的情况下,no-cache、must-revalidate在缓存校验方面的差别。

接下来,我们再看下,引入缓存服务器后,二者表现的差异点。

备注:下文我们会通过查看Squid的访问日志,来确认缓存服务器的行为。这里对日志中的几个关键字先粗略解释下:

  • TCP_MISS:没有命中缓存。有可能是缓存服务器不存在资源的副本,也有可能资源副本已过期。
  • TCP_MEM_HIT:命中了缓存。缓存服务器存在资源的副本,并且副本未过期。

再次贴上之前的图。

 

Cache-Control: no-cache

用例1:chrome第一次访问资源

chrome访问截图如下:200 ok

squid日志:TCP_MISS,表示没有命中本地资源副本。


  1. 1477501799.573 17 127.0.0.1 TCP_MISS/200 299 GET http://127.0.0.1:3000/no-cache - HIER_DIRECT/127.0.0.1 text/html 

用例2:chrome再次访问该资源。且源服务器上,该资源未变化

访问地址:http://127.0.0.1:3000/no-cache

第一次访问略。第二次访问,chrome访问截图如下:

squid访问日志如下:TCP_MISS/304 。表示缓存服务器 联系了 源服务器,发现内容没变化,于是返回304。


  1. 1477501987.785 1 127.0.0.1 TCP_MISS/304 238 GET http://127.0.0.1:3000/no-cache - HIER_DIRECT/127.0.0.1 - 

用例3:chrome再次访问该资源。且源服务器上,该资源已变化

访问地址:http://127.0.0.1:3000/no-cach...

备注:change=1 表示强制每次访问源服务器,返回的资源都是新的。

第一次访问略。第二次访问,chrome截图如下,状态码为200。

从squid日志来看,缓存服务器 访问 源服务器,并返回200给浏览器。


  1. 1477647837.216 1 127.0.0.1 TCP_MISS/200 299 GET http://127.0.0.1:3000/no-cache? - HIER_DIRECT/127.0.0.1 text/html 

Cache-Control: must-revalidate

用例1:缓存服务器 已存在 资源副本,且该资源副本 未过期

访问地址:http://127.0.0.1:3000/must-re...

备注:max-age=900表示资源有效期是900s

步骤一:

chrome第一次访问 该资源,缓存服务器上没有该资源副本,于是访问源服务器。最终,缓存服务器给浏览器返回200。此时,缓存服务器squid上有了资源的副本。

步骤二:

firefox第一次访问 该资源(900s内)。缓存服务器上已有该资源副本,且该副本未过期。于是,缓存服务器给firefox返回该资源副本,且状态码为200。(缓存命中)

为了验证步骤二中,缓存服务器 返回的是本地资源的副本,查看squid日志。其中,第二条就是firefox的访问记录,TCP_MEM_HIT/200表示命中本地缓存。


  1. 1477648947.594 5 127.0.0.1 TCP_MISS/200 325 GET http://127.0.0.1:3000/must-revalidate? - HIER_DIRECT/127.0.0.1 text/html 
  2.  
  3. 1477649012.625 0 127.0.0.1 TCP_MEM_HIT/200 333 GET http://127.0.0.1:3000/must-revalidate? - HIER_NONE/- text/html  

用例2:缓存服务器 已存在 资源副本,该资源副本已过期,但源服务器上 资源未改变

访问链接:http://127.0.0.1:3000/must-re...

用chrome先后访问该资源,其间间隔超过10s。第二次访问时,chrome收到响应如下。

查看squid日志。可以看到,状态为TCP_MISS/304,表示本地副本已过期,跟源服务器进行校验,发现源服务器上资源未改变。于是,给浏览器返回304。


  1. 1477649429.105 11 127.0.0.1 TCP_MISS/304 258 GET http://127.0.0.1:3000/must-revalidate? - HIER_DIRECT/127.0.0.1 - 

用例3:缓存服务器 已存在 资源副本,该资源副本 已过期,但源服务器上 资源已改变

访问地址:http://127.0.0.1:3000/must-re...

用chrome先后访问该资源,其间间隔超过10s。第二次访问时,chrome收到响应如下

squid日志如下,状态都是TCP_MISS/200,表示没有命中缓存。


  1. 1477650702.807 8 127.0.0.1 TCP_MISS/200 325 GET http://127.0.0.1:3000/must-revalidate? - HIER_DIRECT/127.0.0.1 text/html 
  2.  
  3. 1477651020.516 4 127.0.0.1 TCP_MISS/200 325 GET http://127.0.0.1:3000/must-revalidate? - HIER_DIRECT/127.0.0.1 text/html  

对比结论

以下针对的都是浏览器第n次访问资源。(n>1)

不考虑缓存服务器

首部 本地缓存是否过期 源服务器资源是否改变 是否重新校验 状态码
no-cache 不确定 304
no-cache 不确定 200
must-revalidate 是/否 200(来自浏览器缓存)
must-revalidate 304
must-revalidate 200

考虑缓存服务器

首部本地缓存是否过期缓存服务器副本是否过期源服务器资源是否改变是否重新校验状态码

首部 本地缓存是否过期 缓存服务器副本是否过期 源服务器资源是否改变 是否重新校验 状态码
no-cache 不确定 不确定 304
no-cache 不确定 不确定 200
must-revalidate 是/否 是/否 200(来自浏览器缓存)
must-revalidate 是/否 304(来自缓存服务器)
must-revalidate 304
must-revalidate 200

写在后面

经过一轮对比测试,发现no-cache、must-revalidate这两个值还是蛮有意思的。实际上,由于篇幅原因,这里还有一些内容尚未进行对比实验。比如:

  • 当must-revalidate或no-cache跟max-stale一起使用时的表现。
  • no-cache跟max-age=0, mustvalidate的区别。
  • no-chche制定具体的字段名时,跟不指明具体字段名时,缓存校验行为上的区别。
  • proxy-revalidate跟must-revalidate的区别。
  • 缓存服务器本身优化算法对实验结果的影响。

对比实验过程比较枯燥繁琐,如有不严谨或错漏的地方,敬请指出 :)

这里留个经常会碰到的问题,供读者探讨:no-cache跟max-age=0, mustvalidate的区别。

作者:程序猿小卡_casper

来源:51CTO

时间: 2024-08-07 18:01:49

web性能优化之:no-cache与must-revalidate深入探究的相关文章

HTTP/2 与 WEB 性能优化(三)

在连续写了两篇关于「HTTP/2 与 WEB 性能优化」的文章后,今天来写这个系列的最后一篇.在正式开始之前,我们先来简单回顾下之前两篇文章: 「HTTP/2 与 WEB 性能优化(一)」的结论是:HTTP/2 的 Server Push 机制,可以让重要的 JS.CSS 等资源尽快加载,从而不再需要 HTTP/1 中「将重要资源内联在页面头部」的优化方案了. 「HTTP/2 与 WEB 性能优化(二)」的结论是:HTTP/2 支持了多路复用,HTTP 连接变得十分廉价,之前为了节省连接数所采用

java web性能优化问题

问题描述 java web性能优化问题 Java web后台性能优化: 1.可以把数据放在application里面: 2.可以把数据作为static变量的值,放在常量类里: 3.可以把数据放到缓存. 三种方式孰优孰劣,以及各自有什么优缺点? 解决方案 Java Web性能优化Java Web性能优化Java Web性能优化原则

Apache的压力测试以及web性能优化的常用知识总结_Linux

什么是带宽? 误解:"数据在线路中的移动速度"."数据的传输速度" 我们所说的带宽是指数据的发送速度,比如百兆网卡,指网卡的最大发送速度是100Mbps,也就是说网卡在一秒钟最多可以发送100Mb的数据:相关的因素: 数据发送装置将二进制信号传送到线路的能力,也称信号传输频率,以及另一端数据接收装置对二进制信号接收的能力,也包括线路对传输频率的支持程度: 数据传输介质的并行度,等价于计算机系统总线宽度的概念:   习惯与约定 b:比特单位 bit: B:字节单位 B

Web性能优化:What? Why? How?

为什么要提升web性能? Web性能黄金准则:只有10%~20%的最终用户响应时间花在了下载html文档上,其余的80%~90%时间花在了下载页面组件上. web性能对于用户体验有及其重要的影响,根据著名的`2-5-8`原则: 当用户在2秒以内得到响应,会感觉系统的响应非常快 当用户在2-5秒之内得到响应,会感觉系统的响应速度还可以 当用户在5-8秒之内得到响应,会感觉系统的响应非常慢,但还可以接受 当用户在8秒之后都没有得到响应,会感觉系统糟透了,甚至系统已经挂掉:要么打开竞争对手的网站,要么

Web性能优化系列 10个提升JavaScript性能的技巧_javascript技巧

Nicholas Zakas是一位 JS 大师,Yahoo! 首页的前端主程.他是<高性能 Javascript>的作者,这本书值得每个程序员去阅读. 当谈到 JS 性能的时候,Zakas差不多就是你要找的,2010年六月他在Google Tech Talk发表了名为<Speed Up Your Javascript>的演讲. 但 Javascript 性能优化绝不是一种书面的技术,Nicholas 的技术演进列出了10条建议,帮助你写出高效的 JS 代码. 1. 定义局部变量 当

mysql数据库优化与mysql在web性能优化

数据库语句:     Ddl(数据定义语言)    alter  create   drop         Dml(数据操作语言)   inset  delete  update       Dtl(数据事务语言)  conmmit  rollback   savepoint       Select       Dcl(数据控制语句) grant赋权限  revoke回收        Mysql数据库优化: 1.  数据库表 要设计合理(符合3NF,有时候也需要适当的逆范式) 2.  Sq

web性能优化之javascript性能调优_javascript技巧

JavaScript 是一个比较完善的前端开发语言,在现今的 web 开发中应用非常广泛,尤其是对 Web 2.0 的应用.随着 Web 2.0 越来越流行的今天,我们会发现:在我们的 web 应用项目中,会有大量的 JavaScript 代码,并且以后会越来越多.JavaScript 作为一个解释执行的语言,以及它的单线程机制,决定了性能问题是 JavaScript 的软肋,也是 web 软件工程师们在写 JavaScript 需要高度重视的一个问题,尤其是针对 Web 2.0 的应用.绝大多

HTTP/2 与 WEB 性能优化(一)

今年二月份,Google 宣布将在 16 年初放弃对 SPDY 的支持,随后 Google 自家支持 SPDY 协议的服务都切到了 HTTP/2.今年 5 月 14 日,HTTP/2 以 RFC 7540 正式发布.目前,浏览器方面,Chrome 40+ 和 Firefox 36+ 都正式支持了 HTTP/2;服务器方面,著名的 Nginx 表示会在今年底正式支持 HTTP/2. 不得不说这几年 WEB 技术一直在突飞猛进,爆炸式发展.昨天还觉得 HTTP/2 很遥远,今天已经遍地都是了.对于新

Web网站性能优化的相关技术

中介交易 SEO诊断 淘宝客 云主机 技术大厅 Web站点性能问题吸引或者迫使越来越多的人投入到这个问题的研究中来,产生了很多解决方案.下面是我根据自身的理解对这些技术进行了归类总结,如有不足之处欢迎拍砖. 一.提高服务器并发处理能力 我们总是希望一台服务器在单位时间内能处理的请求越多越好,这也成了web服务器的能力高低的关键所在.服务器之所以可以同时处理多个请求,在于操作系统通过多执行流体系设计,使得多个任务可以轮流使用系统资源,这些资源包括CPU.内存以及I/O等.这就需要选择一个合适的并发