专栏名称: SegmentFault思否
SegmentFault (www.sf.gg)开发者社区,是中国年轻开发者喜爱的极客社区,我们为开发者提供最纯粹的技术交流和分享平台。
目录
相关文章推荐
OSC开源社区  ·  Bun ... ·  2 天前  
程序员的那些事  ·  OpenAI ... ·  2 天前  
程序员小灰  ·  3个令人惊艳的DeepSeek项目,诞生了! ·  3 天前  
OSC开源社区  ·  2024: 大模型背景下知识图谱的理性回归 ·  5 天前  
程序员小灰  ·  DeepSeek做AI代写,彻底爆了! ·  6 天前  
51好读  ›  专栏  ›  SegmentFault思否

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

SegmentFault思否  · 公众号  · 程序员  · 2017-09-27 08:00

正文

引言

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

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

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

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

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

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

no-cache、must-revalidate简介

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

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

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

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

  • 浏览器:资源请求直接发起方。

  • 源服务器:资源实际提供方。

  • 缓存服务器:在浏览器、源服务器之间架设的中间服务器,由它代替浏览器,向源服务器发起资源请求;

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

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

对比测试场景、环境准备

对比测试场景

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

  1. 浏览器 直接访问 源服务器。

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

环境准备

  • 操作系统: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. cd tech-experiment/2016.10.25-cache-control/

  3. npm install

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

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

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

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

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

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

  1. cd connect-directly

  2. 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

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

  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-cache?change=1 备注: 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变化了,表示源服务器资源已发生变化。于是状态码为 200OK ,源服务器返回新版本的资源给浏览器。

  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-revalidate 可选参数说明:

  • max-age :源站返回的内容, max-age 是多少(单位是s)。

  • change :源站返回的内容,是否变化,如果是 1 ,则变化。

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

访问地址:http://127.0.0.1:3000/must-revalidate?max-age=10 备注: 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后),返回 304NotModified

  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-revalidate?max-age=10&change=1

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

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

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

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

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

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

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

  • TCP MEM HIT:命中了缓存。缓存服务器存在资源的副本,并且副本未过期。

再次贴上之前的图。

Cache-Control: no-cache

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

chrome访问截图如下: 200ok

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-cache?change=1 备注: 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-revalidate?max-age=900 备注: max-age=900 表示资源有效期是900s

步骤一:

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

步骤二:

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

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







请到「今天看啥」查看全文