HTTP 协议的缓存机制涉及到多个请求头字段,而且整个缓存机制的细节行为也存在各种情况的差异,譬如说什么时候访问本地缓存不发送请求,什么时候发送请求查看资源是否更新,获取 response 什么情况下更新缓存等。以前我对此一知半解只是笼统的知道一些概念,譬如 Cache-Control 可以控制缓存的时间和是否需要缓存,但是缓存过期后的行为,有缓存后浏览器是否有 http 请求都不甚了解。所以特地 google 下,此篇是对此的知识梳理。

协议概述

什么情况下可以使用本地缓存?譬如说我们用 get 方式请求了一个资源 http://mytest.domain.com/static/images/bg.png,那么我们下次再请求这个图片资源的时候符合哪些条件可以使用本地缓存呢?

url 必须是 http://mytest.domain.com/static/images/bg.png,如果是 http://mytest.domain.com/static/images/bg.png?t=12312321 就会发起新的请求,因为 url 不同。

发送请求的 method 必须可被缓存,譬如 get。

第一次请求 response(即本地缓存)如果有一个 Vary 头,他的值列出的是一系列 http header,第二次请求的请求头中那些在 Vary 值中所列的头,必须和第一次请求相同(具体规则)。

第二次请求不包含请求头 Pragma: no-cache

第二次请求不包含请求头 Cache-Control: no-cache|max-age=0

第一次请求的 response(即本地缓存)不包含 Cache-Control: no-cache

本地缓存没有过期

或者虽然本地缓存已经过期,但是服务器验证缓存和服务器资源一致,允许使用本地缓存的情况(即获得304 response)

注2:response header中不仅仅可以 Cache-Control: no-cache,还可以 Cache-Control: no-cache="Set-Cookie" 详见

如何计算本地缓存是否过期

浏览器是通过比较缓存剩余有效时间和当前缓存已存在时间来判断的:response_is_fresh = (freshness_lifetime > current_age)。freshness_lifetime 取值优先级次序如下列表所示(排在上面的优先级越高):

Cache-Control: s-maxage=xx

Cache-Control: max-age=xx

Expires: xxxxx

按规则进行计算(推测)

注1;如果有多个重复的上述头,那么是非法的,视作 response(资源)过期

freshness_lifetime 计算(推测)规则:

规范并没有给出具体的算法,但是给出了最坏情况(but does impose worst-case constraints on their results),如果 response(资源)有 Last-Modified 头,那么推荐用从当前到lastmodified这个时间段的 10% 作为 freshness_lifetime,并且 response(资源)的 current_age 如果已经超过24小时,必须在这个 response 上加上113 warn-code头。很少有浏览器实现了freshness_lifetime的自助计算(推测),所以还是还是鼓励给出上述显式的1 - 3三种情况。

current_age 计算规则:

泛泛来说就是 response(资源)在本地的驻足时间加上网络传输时间,因为网络传输时间的计算有多个条件,规范实在看的我头晕,所以具体计算规则详见规范

本地缓存过期,如何通过服务器验证缓存的是否依然有效(即304的情况)

首先,如果第一次的 response(资源)头中显示申明了一些禁止缓存的头(譬如:"no-store" or "no-cache" 等等),就不存在过期不过期的问题,因为这个资源不允许缓存。其次,过期缓存也不一定不可用,如果在断网或者第二次请求带上 max-stale 这个请求头,那么浏览器可以使用过期的缓存(masx-stale 表示在缓存过期后多少时间内浏览器依然可以使用缓存)。碰到过期缓存,浏览器可以发送一个条件请求(conditional request)。这个请求的 url 依然是第一次请求的 url,只是会带上些当前资源的一些信息,以供服务器验证这个缓存是否依然可用还是需要更新:

response(资源)的 Last-Modified 头所带的值会放到条件请求的 If-Modified-Since 头中,或者是 If-Unmodified-Since 又或者 If-Range。

response(资源)的 ETag 头所带的值会放到条件请求的 If-None-Match 头中,或者 If-Match 又或者 If-Range。

服务器会根据不同的条件请求头来验证资源,具体的行为详见规范,这里不细致展开。针对条件请求,服务器返回会有三种情况:

一个带有304 status code 的返回。表示缓存可以被更新和重用。

一个带有 body 的完整的 response。表示用这个 response 作为请求的返回,并且视条件可以用这个完整的 response 替换浏览器原有的缓存(此资源)。

如果返回一个5xx的 response,那么浏览器可以选择就显示这个5xx的返回,或者使用本地缓存(尽管可能是过期的)- 规范没有规定应该选择哪种处理,应该是取决于浏览器的行为。

如果是一个304的返回,规范说这个返回可以更新本地缓存,更新策略分三种:

如果这个304 response 带有资源有效性的强验证头,那么浏览器会寻找本地缓存,寻找那些带有同样强验证头的缓存,然后用这个最新的 response 去更新这些匹配的缓存(同一个资源可能浏览器保存有多份缓存,譬如日期不同等)。

如果这个304 response 带有资源有效性的弱验证头,那么浏览器同样会找相匹配的缓存,但是只会更新最新的那条匹配的缓存。

如果这个304 response 没有带有任何资源有效性验证头,并且浏览器缓存只有一份,并且这份也同样没带有任何资源有效性验证头,那么浏览器就会用这个304 response,更新本地缓存。

协议流程图

假设第一次请求一个资源,返回 header 里面带上如下字段:

Cache-Control: max-age=600

Last-Modified: Wed, 28 Aug 2013 10:36:42 GMT

ETag: "124752e0d85461a16e76fbdef2e84fb9"

抛开细枝末节的东西,那么第二次请求通常大致流程图如下:

当前资源缓存是否过期:response_is_fresh = (freshness_lifetime > current_age)

|

-----------------------------------

| |

是 否

| |

发送请求,带上请求头 从本地缓存中获取资源(不发请求)

If-Modified-Since: 此资源Last-Modified的值

If-None-Match: 此资源ETag的值

|

服务器根据 If-Modified-Since 和 If-None-Match

两个值判断资源是否更新过

|

-------------------------

| |

是 否

| |

返回一个 status code:200 的 response 返回一个 status code:304 的 response

response body 里面是请求的资源 response body 为空

| |

浏览器用 response body里面的资源 依然从本地缓存里面获取资源

替换本地缓存中的资源

特殊情况

当你去浏览器验证的时候可能会碰到一些特殊情况,就是缓存有效,但是你刷新浏览器依然发送的条件请求。其实是因为浏览器在请求头中加入了一些料,譬如: Cache-Control: max-age=0。你刷新的方式可以有很多种,譬如:按F5,按ctrl+F5,在地址栏按回车等等。这些不同的行为都会影响浏览器发送请求的行为。这里有一些参考《在浏览器地址栏按回车、F5、Ctrl+F5刷新网页的区别》

参考资料

缓存服务器协议有哪些,HTTP 协议的缓存机制概述相关推荐

  1. php管理varnish,php实现监控varnish缓存服务器的状态,php监控varnish缓存_PHP教程

    php实现监控varnish缓存服务器的状态,php监控varnish缓存 当varnish和网站部署在同一台服务器上的时候,我们不可能随时登录上服务器去查看varnish的命中率,没想到有大神早就写 ...

  2. varnish 缓存php,php实现监控varnish缓存服务器的状态,php监控varnish缓存

    php实现监控varnish缓存服务器的状态,php监控varnish缓存 当varnish和网站部署在同一台服务器上的时候,我们不可能随时登录上服务器去查看varnish的命中率,没想到有大神早就写 ...

  3. 桌面缓存服务器,primocache 把内存虚拟成硬盘缓存的硬盘优化软件

    primocache 是一款专业的硬盘优化软件,它的原理是把内存虚拟成硬盘缓存来实现硬盘优化,本次小编发布的是primocache,中包含两个版本分别是PrimoCache普通版和PrimoCache ...

  4. memcached 缓存服务器

    Memcached 缓存服务器 Memcached 是高性能的分布式内存缓存服务器. 一般的使用目的是,通过缓存数据库查询结果,减少数据库访问次数,以提高动态web应用的速度.提高可扩展性. 主要特点 ...

  5. Memcached:高性能的分布式内存缓存服务器

    Memcached:高性能的分布式内存缓存服务器 特征: u 协议简单: n 基于文本行的协议 u 基于libevent的事件处理: n 程序库,能实现连接数的增加,O(1)性能 u 内置内存存储方式 ...

  6. 压力测试及缓存服务器

    第一篇 WEB压力测试 一.常用工具 常用压力测试工具:ab,httpd_load,webbench,seige. 仅仅作为测试使用,与实际能力区别也挺大的. 比较好的测试工具:惠普公司的loadru ...

  7. Cache Server缓存服务器

    Preferences偏好设置-Cache Server缓存服务器 5.Cache Server:缓存服务器,对缓存服务器进行设置,在选中"Use Cache Server"选项后 ...

  8. 如何应对缓存服务器宕机的情况

    假如所有缓存服务器都宕机,而且不能很快恢复,并且假设数据库服务器能够支撑,在代码中如何应对这样的情况? 之前的做法是在读缓存的地方捕获异常并写入日志,然后直接从数据库读取数据:在写缓存的地方捕获异常并 ...

  9. 如何应对java服务器宕机_代码中如何应对缓存服务器宕机的情况

    今天在演练这样一个场景--假如所有缓存服务器都宕机,而且不能很快恢复,并且假设数据库服务器能够支撑,在代码中如何应对这样的情况? 之前的做法是在读缓存的地方捕获异常并写入日志,然后直接从数据库读取数据 ...

  10. 代理缓存服务器知识点整理

    [代理缓存服务器知识点整理] 一.http相关 1.正常http请求跟代理http请求的区别 常规的http请求头部:GET /index.html HTTP/1.1 Host:www.xuxiong ...

最新文章

  1. vivado----fpga硬件调试 (五) ----找不到ila核问题及解决
  2. GDCM:gdcm::DataSet的测试程序
  3. typescript获取数据库数据_肿瘤药敏多组学数据库(GDSC)的数据介绍和获取
  4. 中南大学12月13日考c语言,中南大学2010级C语言试卷
  5. 超长干货 | Kubernetes命名空间详解
  6. 如何理解Cookie、Session和Token
  7. Xcode 9有什么新功能?
  8. Java商城系统后端和小程序模板、毕业设计下载
  9. java基于springboot的酒店预约管理平台系统
  10. uc看视频显示服务器有点忙,uc浏览器常见问题集锦(一)
  11. 10分钟让你掌握Linux常用命令(+2万+++收藏)
  12. 体育专业国培计算机感言,信息技术国培感言
  13. Wing Pro 7中文版
  14. Django-应用与分布式路由
  15. RabbitMQ - 4种Exchange类型
  16. Android开源 -- 开源的基于 Material Design设计的豆瓣的Android客户端“豆芽”
  17. 自由轴法 matlab,自由轴法与固定轴法 三亿文库
  18. Pycharm专业版最新版下载安装(社区版和专业版并存)
  19. 计算机显示器图片怎么铺满全屏,win10电脑显示器屏幕不能铺满怎么办_win10电脑显示不能铺满屏幕处理方法-win7之家...
  20. 读格林斯潘回忆录-9

热门文章

  1. 海外弱网下的在线视频平台优化实践​
  2. JVM之强引用、软引用、弱引用、虚引用
  3. nginx+upsync+consul 构建动态nginx配置系统
  4. 多窗口管理器Tmux - 从入门到精通
  5. springsession使用redis
  6. go语言switch中判断多个值
  7. java基础---流程控制
  8. leetcode 380. Insert Delete GetRandom O(1) | 380. O(1) 时间插入、删除和获取随机元素(Java)
  9. 【Verilog语法】PC-relatve branch 以及 Delay Slot 的含义
  10. spdk-nvmf指南