1. http协议中关于过期的规定
由于http协议是支持缓存(cache)机制的,包括客户端浏览器的Cache(如ie的temporary internet files)以及web cache(如squid),这就决定了必须有一种机制使得这些被浏览器或squid缓存住的内容要定期更新。
对于内容的更新,一种方法是浏览器的功能来清除缓存,或者CDN的刷新系统来刷掉内容。这种做法的缺点是,需要人工干预。
另一种更新内容的方法就是通过http协议的过期机制来更新内容,这种过期机制是通过客户端的请求头与服务器端的响应头中的相关header来实现的。对于过期的内容,客户端或cache会向源站/上层cache发出验证的请求,如果在源站/上层cache上面这些内容已经改变过,客户端会重新获得这些内容。这种方法是本文要介绍的重点。
Date与Expires
Date和Expires都是表示绝对时间的概念,其不同点在于:
Date给出的是响应发出的绝对时间。
一个Date头域中的HTTP-date不应该是一个消息产生时刻之后的日期和时间。它应该表示与消息产生时的日期和时间的最近似值,除非没有办法产生一个合理的精确日期和时间。
Expires给出响应的内容过期的绝对时间。一个陈旧的缓存项不能被缓存(一个代理缓存或一个用户代理的缓存)返回给客户端,除非此缓存项被源服务器(或者被一个拥有实体的保鲜副本的中间缓存)验证。若响应包含一个Cache-Control 头域,并且含有max-age 缓存控制指令(参见14.9.3节),则此指令覆盖Expires头域。如果一响应包含一s-maxage缓存控制指令,那么对于一共享缓存(不能对私有缓存)来说,s-maxage指定的值将会覆盖max-age缓存控制指令或Expires头域。如果一响应包含一s-maxage缓存控制指令,那么对于一共享缓存(不能对私有缓存)来说,s-maxage指定的值将会覆盖max-age缓存控制指令或Expires头域。
Date与Expires通常是格林尼治标准时间(如果后面带有GMT),也就是比北京时间早8个小时。
请求:
max-age
表明客户端愿接受这样一个响应,此响应的年龄不大于客户端请求里max-age指定时间(以秒为单位)。除非max-stale缓存控制指令也包含在请求里,否则客户端是不能接收一个陈旧响应的。
min-fresh
表明客户端愿接受一个这样的响应,其保鲜寿命不小于响应当前年龄(current age,见13.2.3节关于current_age的定义)与客户端请求里的min-fresh指定的时间之和(以秒为单位)。也就是说,客户端想要一个响应至少在min-fresh指定的时间内是保鲜的。
Age与Cache-Control:max-age
age是指:自从这个响应在源站服务器上生成以来(而不是源站内容修改以来!!),到现在所经历的秒数。
max-age是指:一个响应被源站发出后,在cache当中存活的时间,换句话说,一个响应的Age值如果超过了max-age,就认为这个响应是过期的。
Age与max-age比Expires更加优先!
If-Modified-Since与Last-Modified
If-Modified-Since是http请求头的一部分,它表示客户端向源站询问“这个内容自从x年x月x日x时起,是否变过?”
如果源站发现该内容变过,则会返回一个200OK的响应,并把新的内容发回来给客户端。
如果源站发现内容没有变过,则会返回一个304的响应,告诉客户端“没有改变过,你的内容还是可以用的”,这种情况下就不用发送内容了,可以大大节省传输带宽。
注意:
如果客户端发的If-Modified-Since后面的日期是非法的日期,源站将直接返回200OK+新内容。If-Modified-Since后面跟的日期是客户端上一次接到的响应中,Last-Modified的值。
Last-Modified是响应头的一部分,是源站给出的,一个内容在源站上最终更新的时间。
对于静态内容,Last-Modified是文件的更新时间,对于动态内容,取决于源站的具体实现。
If-Unmodified-Sincey与Last-Modified
If-Unmodified-Since请求头域被用于一个方法使之成为条件方法。如果请求资源自从此头域指定时间开始之后没有改变,那么服务器应该执行此请求就像If-Unmodified-Since头域不存在一样。如果请求变量(variant,译注:见术语)在此头域指定时间后以后已经改变,那么服务器不能执行此请求,并且必须返回412(前提条件失败)状态码。
Etag与If-None-Match
有的时候,Last-Modified 与 If-Modified-Since不能够可靠地标示内容的改变,这就需要Etag等更加可靠的打标签的机制。Etag是响应头的一部分,是源站对内容所打的一个标签,用来标示这个文件,这个标签当且仅当内容变化才会变化,就像md5码一样。
与md5码不同的是,打Etag不需要读取整个文件的内容,比md5消耗的资源要少得多。Etag起到的作用跟Last-Modified差不多,都是标示内容的变化,只是比Last-Modified更可靠。
If-None-Match是请求头的一部分,它表示客户端向源站询问“这个内容的标签还是不是xxxxxx?”如果源站发现该内容变过,则会返回一个200OK的响应,并把新的内容发回来给客户端。如果源站发现内容没有变过,则会返回一个304的响应,告诉客户端“没有改变过,你的内容还是可以用的”,这种情况下就不用发送内容了,可以大大节省传输带宽。
如果If-None-Match头域里的任何实体标签(entity tag)假设与一个相似的GET请求(假设没有If-None-Match头域)返回实体的实体标签相匹配,或者,如果“*”被给出并且服务器关于那个资源的任何当前实体存在,那么服务器不能执行此请求方法,除非资源的修改日期和请求里If-Modified-Since头域(假设有的话)里提供的日期匹配失败(译注:匹配失败说明资源改变了)。换言之,如果请求方法是GET或HEAD,那么服务器应以304(没有改变)来响应,并且包含匹配实体的相关缓存头域(特别是Etag) 。对于所有其它方法,服务器必须以412(先决条件失败)状态码响应。
Etag与If-Match
如果If-Match头域里任何一个实体标签假设与一个相似GET请求(没有If-Match头域)返回响应里实体的实体标签相匹配,或者如果给出“*”并且请求资源的当前实体存在,那么服务器可以执行请求方法就好像If-Match头域不存在一样。
如果没有一个实体标签匹配,或者给出了“*”但服务器上没有当前的实体,那么服务器不能执
行此请求的方法,并且返回412响应(先决条件失败)。