缓存保持副本的新鲜

========================摘自《HTTP权威指南》=================================

可能不是所有已缓存副本都与服务器上的文档一致。毕竟,这些文档会随着时间发生变化。报告可能每个月都会发生变化。在线报纸每天都会发生变化。财经数据可能每过几秒就会发生变化。如果缓存总是提供的老数据,就会变得毫无用处。已缓存的数据要与服务器的数据保持一致。

HTTP有一些简单的机制可以在不要求服务器记住有哪些缓存拥有文档副本的情况下,保持已缓存数据和服务器数据之间充分一致。HTTP将这些简单的机制称为文档过期(document expiration)和服务器再验证(server revalidation)。

1、  文档过期

通过特殊的HTTP Cache-Control首部和Expires首部,HTTP让原始服务器向每个文档附加一个“过期日期”。就像一夸脱牛奶上的过期日期一样,这些首部说明了在多长时间内将这些内容视为新鲜的。

在缓存文档过期之前,缓存可以以任意频率使用这些副本,而无需与服务器联系—当然,除非客户端请求中包含有阻止提供已缓存或未验证资源的首部。但一旦已缓存文档过期,缓存就必须与服务器进行核对,询问文档是否被修改过,如果被修改过,就要获取一份新鲜(带有新的过期日期)的副本。

2、  过期日期和使用期

服务器用HTTP/1.0+的Expires首部或HTTP/1.1的Cache-Control:max-age响应首部来指定过期日期,同时还会带有响应主体。Expires首部和Cache-Control首部所做的事本质上时一样的,但是由于Cache-Control首部使用的是相对时间而不是绝对日期,所以我们倾向于使用比较新的Cache-Control首部。绝对日期依赖于计算机时钟的正确设置。

3、  服务器再验证

仅仅是已缓存文档过期了并不意味着它和原始服务器上目前处于活跃状态的文档由实际的区别;这只是意味着到了要进行核对的时间了。这种情况被称为“服务器再验证”,说明缓存需要询问原始服务器文档是否发生了变化。

(1)、如果再验证显示内容发生了变化,缓存会获取一份新的副本,并将其存储在旧的文档位置上,然后将文档发送给客户端;

(2)、如果再验证显示内容没有发生变化,缓存只需要获取新的首部,包括一个新的过期日期,并对缓存中的首部进行更新就行了。

缓存并不一定要为每条请求验证文档的有效性—只有在文档过期时它才需要与服务器进行再验证。这样不会提供陈旧的内容,还可以节省服务器的流量,并拥有更好的用户响应时间。

HTTP协议要求行为正确的缓存返回下列内容之一:

A、“足够新鲜的”已缓存副本;

B、与服务器进行再验证,确认其仍然新鲜的已缓存副本;

C、如果需要与之进行再验证的原始服务器出故障了,就返回一条错误报文;

D、附有警告信息说明内容可能不正确的已缓存副本;

4、用条件方法进行再验证

HTTP的条件方法可以高效的实现再验证。HTTP允许缓存向服务器发送一个“条件GET”,请求服务器只有在文档缓存中现有的副本不同时,才回送对象主体。通过这种方式,将新鲜度检查与对象获取结合成了单个条件GET。向GET请求报文中添加一些特殊的条件首部,就可以发起条件GET。只有条件为真时,Web服务器才返回对象。

HTTP定义了5个条件请求首部。对缓存再验证来说最有用的2个首部是If-Modified-Since和If-None-Match。所有的条件首部都以前缀“If-”开头。表7-3列出了在缓存再验证中使用的条件请求首部。

5、  If-Modified-Since:Date再验证

最常见的缓存再验证首部是If-Modified-Since。If-Modified-Since再验证请求通常被称为IMS请求。只有自某个日期之后资源发生了变化的时候,IMS才会指示服务器执行请求:
(1)、如果自指定日期后,文档被修改了,If-Modified-Since条件就为真,通常GET就会成功执行。携带新首部的新文档会被返回给缓存,新首部除了其他信息之外,还包含了一个新的过期日期。

(2)、如果自指定日期后,文档没有被修改过,条件就为假,会向客户端返回一个小的304 Not Modified响应报文,为了提高有效性,不会返回文档的主体。这些首部是放在响应中返回的,但只会返回那些需要在源端更新的首部。比如Content-Type首部通常不会被修改,所以通常不需要发送,一般会发送一个新的过期日期。

If-Modified-Since首部可以Last-Modified服务器响应首部配合工作。原始服务器会将最后的修改日期附加到所提供的文档上去。当缓存要对已缓存文档进行再验证时,就会包含一个If-Modified-Since首部,其中携带有最后修改已缓存副本的日期:

If-Modified-Since :<cached Last-Modified data>

如果在此期间内容被修改了,最后的修改日期就会有所不同,原始服务器就会回送新的文档。否则服务器会注意到缓存的最后修改日期与服务器文档当前的最后修改日期相符,会返回一个304 Not Modified响应。

6、  If-None-Match:实体标签再验证

有些情况下仅使用最后修改进行再验证是不够的。

(1)、有些文档可能会被周期性的重写(比如,从一个后台进程中写入),但实际包含的数据常常是一样的。尽管内容没有发生变化,但修改日期会发生变化。

(2)、有些文档可能被修改了,但所做的修改并不重要,不需要让世界范围内的缓存都重装数据(比如对拼写和注释的修改)。

(3)、有些服务器无法准确地判断其页面的最后修改日期。

(4)、有些服务器提供的文档会在亚秒间隙发生变化(比如,实时监视器),对这些服务器来说,以一秒为粒度的修改日期可能就不够用了。

为了解决这些问题HTTP允许用户对被称为实体标签(ETag)的“版本标识符”进行比较。实体标签是附加到文档是的任意标签(引用字符串)。他们可能包含了文档的序列号或版本名,或者是文档内容的校验和及其他指纹信息。

当发布者对文档进行修改时,可以修改文档的实体标签来说明这个新版本。这样,如果实体标签被修改了,缓存就可以用If-None-Match条件首部来GET文档的新副本了。

7、  强弱验证器

缓存可以用实体标签来判断,与服务器相比,已缓存的版本是不是最新的(与使用最近修改日期的方式很像)。从这个角度来看,实体标签和最近修改日期都是缓存验证器(cache validator)。

有时,服务器希望在对文档进行一些非实质性或不重要的修改时,不要使所有的已缓存副本都失效。HTTP/1.1支持“弱验证器”。如果只对内容进行了少量修改,就允许服务器声明那是“足够好”的等价体。

只要内容发生了变化,强验证器就会发生变化。弱验证器允许对一些内容进行修改,但内容的主要含义发生变化时,通常它还是会发生变化的。有些操作不能用弱验证器来实现(比如有条件地获取部分内容),所以,服务器会用前缀“W/”来标识弱验证器。

ETag:W/”v2.6”

If-None-Match:W/”v2.6”

不管相关的实体值以何种发生变化,强实体标签都要发生变化。而相关实体在语义上发生了比较重要的变化时,弱实体标签也要发生变化。

注意,原始服务器一定不能为两个不同的实体重用一个特定的强实体标签值,或者为两个语义不同的实体重用一个特定的弱实体标签值。不管过期时间是多少,缓存条目都可能会留存任意长的时间,因此,假设缓存不会再次通过它在过去某个时刻获得的验证器,对一个条目进行验证是不合适的。

8、  什么时候应该使用实体标签和最近修改日期

如果服务器回送了一个实体标签,HTTP/1.1客户端就必须使用实体标签验证器。如果服务器只回送了一个Last-Modified值,客户端就可以使用If-modified-since验证。如果实体标签和最后修改日期都提供了,客户端就应该使用这两种再验证方案,这样HTTP/1.0和HTTP/1.1缓存就可以正确的响应了。

除非HTTP/1.1原始服务器无法生成实体标签验证器,否则就应该发送一个出去,如果使用弱实体标签有优势的话,发送的可能就是个弱实体标签,而不是强实体标签。而且,最好同时发送一个最近修改值。

如果HTTP/1.1缓存或服务器收到的请求既带有If-modified-since,又带有实体标签条件首部,那么只有这两个条件都满足时,才能返回304 Not Modified响应。

HTTP之缓存是如何保持副本的新鲜的!的更多相关文章

  1. 前端学HTTP之缓存

    前面的话 Web缓存是可以自动保存常见文档副本的HTTP设备.当Web请求抵达缓存时,如果本地有“已缓存的”副本,就可以从本地存储设备而不是原始服务器中提取这个文档.本文将详细介绍缓存的相关内容 功能 ...

  2. HTTP缓存

    本文是<HTTP权威指南>读书笔记 Web缓存是可以自动保存常见文档副本的设备.当Web请求抵达缓存时,如果本地在“已缓存”的的副本,就可以从本地存储设备而不是原始服务器中提取这个文档.使 ...

  3. 浏览器缓存相关的Http头介绍:Expires,Cache-Control,Last-Modified,ETag

    转自:http://www.path8.net/tn/archives/2745 缓存对于web开发有重要作用,尤其是大负荷web系统开发中. 缓存分很多种:服务器缓存,第三方缓存,浏览器缓存等.其中 ...

  4. HTTP权威协议笔记-7.缓存

    7.1 冗余的数据传输 缓存的作用:当客户端每次访问服务器,服务器都会返回一份相同文件,一些相同的字节会不断的在网络内传输,这样冗余的数据传输会耗尽昂贵的带宽,降低传输速度,加重Web服务器的负载. ...

  5. HTTP中缓存相关

    1.客户端如何区分缓存命中和未命中 两种情况下,返回的状态码都是200,客户端有一个方法可以判断,就是使用Date首部,将Date首部与当前时间进行比较,如果响应中时间日期值比较早,客户端可以认为这是 ...

  6. 关于缓存的tips——HTTP权威指南读书心得(十三)

    上一章介绍了缓存新鲜度判断的基本原理,本章对于缓存新鲜度判断方法进行一些补充(更新间隔略长略长..). 关于缓存的TIPS 服务器可以通过http定义的几种header对可以缓存数据的存在时间进行控制 ...

  7. HTTP缓存机制[译文]

    本文翻译自: https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching ,主要用于个人记录和共享,若有疏漏错误,请不吝指正,谢谢! 通过重用已 ...

  8. 分布式缓存-Memcached

    分布式缓存出于如下考虑,首先是缓存本身的水平线性扩展问题,其次是缓存大 并发下的本身的性能问题,再次避免缓存的单点故障问题(多副本和副本一致性).分布式缓存的核心技术包括首先是内存本身的管理问题,包括 ...

  9. ATS缓存数据结构

    ATS缓存数据结构 HttpTunnel类 数据传输驱动器(data transfer driver),包含一个生产者(producer)集合,每个生产者连接到一个或是多个消费者(comsumer). ...

随机推荐

  1. 最近在折腾在线编辑,研究了下Wopi,下面粘贴出自己Office Online Server2016搭建与部署

    至少需要两台服务器,一台域控制器,一台部署Office Online Server https://docs.microsoft.com/zh-cn/officeonlineserver/office ...

  2. 在.NET Core 3.0 Preview上使用Windows窗体设计器

    支持使用基于Windows窗体应用程序的.NET Core 3.0(预览)的Windows窗体设计器 介绍 截至撰写本文时,Microsoft和社区目前正在测试.NET Core 3.0.如果您在.N ...

  3. 编译 datax

    datax 是阿里巴巴官方开源的一个数据同步工具,可以用于诸多数据源之间的同步,并且使用简单.效率高. datax 官方有提供编译好的版本,可以直接下载,但是其中包含有 BUG. 我最近遇到的一个问题 ...

  4. SQLMap常用教程

    先安装 python环境(2.6.x或2.7版本) ,再将SQLMap 放在安装目录下 注意:sqlmap只是用来检测和利用sql注入点的,并不能扫描出网站有哪些漏洞,使用前请先使用扫描工具扫出sql ...

  5. background 设置文本框背景图

    background 属性的作用是给元素设置背景,它是一个复合属性,常用的子属性如下: background-color 指定元素的背景颜色. background-image 指定元素的背景图像. ...

  6. Python 安装cx_Oracle模块

    1.Python安装cx_Oracle模块需要安装Oracle,并在环境变量中添加Oracle的路径. 2.没有安装Oracle的需要下载一个oci.dll的文件,并把文件的路径添加到path中. 如 ...

  7. Linux目录管理

    Linux文件目录管理 1:目录管理 1)切换目录 # cd  [ 目录名称] 2)退到上一目录 # cd .. 2:创建目录 mkdir  [文件名称] mkdir -p  [文件名称] 递归创建目 ...

  8. 09、日志轮转+rsync同步

    logrotate   -  rotates,  compresses,  and    mails system logs 日志轮转 rotate 日志切割 轮转   切割   备份   归档 常见 ...

  9. Jenkins参数化构建(七)

    一.配置参数化构建过程 主要用来区分分支,使用传参的方式,将分支名称传入脚本中进行拉取代码. 1.1 最常用的是:字符参数.文本参数.  1.2 添加字符参数和文本参数,并配置变量名称  1.3 配置 ...

  10. Mysql 数据库部署(解压免安装)

    下载压缩包,解压. 在根目录下添加my.ini, 复制一下内容,保存. [mysqld] skip-grant-tables #绑定IPv4和3306端口 bind-address = 0.0.0.0 ...