HTTP服务器应当告诉客户端能够将报文缓存多长时间,并且在这个时间范围内,报文的内容是新鲜的(fresh),而服务器是使用这两个响应首部来告诉客户端的:
一,Expires(过期)
该首部主要用在HTTP1.0中,规定文档“过期”的具体时间点,超过此时间则认为文档不是最新的,该头部使用的时间格式是GMT格式,如下所示:
Expires: Sun Mar 20 13:21:12 GMT 2013
该首部存在的问题是客户端和服务器需要进行时钟同步,但这个是一个非常棘手的问题,因为服务器和各个客户端不可能随时运行像Network Time Protocol(网络时间协议, NTP) 进行时钟同步。
为了说明时间不同步导致的问题,假设:
服务器返回一个HTTP响应报文,并且设置Expires为:Sun Mar 2010:00:00 GMT 2012,即告诉客户端该文档在Mar 20 10:00:00 GMT 2012前都是新鲜的,可以直接使用。
但客户端如何判断呢?Expires头设定的过期时间其实是服务器设置的,因此过期时间也是根据服务器的时间为基准点计算的过期时间,但一定该响应到达客户端,则客户端是无法知道此时服务器的时间点是什么时候的,因此客户端只能根据客户端自己的时间基准进行判断,这样就存在三种情况:
1, 客户端和服务器的时钟同步,此时读取客户端当前的时间,然后跟Expires的时间进行对比,若Expires >= 客户端当前时间,则认为文档未过期,可以继续使用。
2, 若客户端时间比服务器时间快,那么此时进行比较,则会使得缓存的有效时间变短了,极端情况下,会使得缓存失效,假如服务器设置的有效缓存时间是10分钟,若客户端比服务器早10分钟,则在客户端看来,该Expires对应的时间已经过了,即响应已经失效;
3, 若客户端比服务器时间慢,那么此时会使得响应的有效缓存时间变长,极端情况下,可能由于缓存时间过长导致数据无法及时进行刷新等问题。
综上,用Expires绝对时间进行控制缓存存在很大的问题,在新的HTTP1.1版本中,则使用新的响应头Cache-Control,并用相对时间来定义过期的机制,这样就客户端和服务器就无须考虑时间同步的问题了。
二,Cache-Control
Cache-Control首部可以用秒数来规定文档的最长使用期 --- 从文档离开服务器之后算起的总计时间,使用期不与时钟同步,因此可以给出更精确的结果。
实际上,Cache-Control头部如同他的名字一样,不仅仅用于控制使用期或者过期,其实是一个控制缓存的综合头部,支持各种指令,并且可以用在HTTP请求和响应中。
报文类型 | 指令 | 说明 |
请求 | no-cache | 不要直接使用缓存中的副本(哪怕缓存还没过期),而需要重新向服务器进行验证,验证之后才能返回。 |
请求 | no-store | 不要返回文档的缓存副本,也不要保存服务器的响应。 |
请求 | max-age | 缓存中的文档不能超过指定的使用期 |
请求 | max-stale | 返回的文档允许过期(根据服务器提供的过期信息计算),但最多不能超过指令中指定的过期值 |
请求 | min-fresh | 返回的文档必须至少在指定的这个时间之内保存新鲜。即文档的有效期必须大于等于min-fresh+当前时间的和。 |
请求 | no-transform | 文档在发送前不能进行转换 |
请求 | only-if-cached | 只有当文档在缓存中才发送,不必联系原始服务器 |
|
|
|
响应 | public | 响应可被任何服务器缓存 |
响应 | Private | 响应可以被缓存,但只能被单个客户端访问 |
响应 | no-cache | 如果该指令伴随一个首部列表的话,那么内容可以被缓存并提供给客户端,但必须先删除所列出的首部; 如果没有指定首部,缓存中的副本在没有重新重新向服务器验证之前不能直接提供给客户端使用。 |
响应 | no-store | 响应不能被保存,因此也说明不允许缓存。主要用在一些敏感的响应。 |
响应 | no-transform | 响应在提供给客户端之前不能做任何形式的修改 |
响应 | must-revalidate | 响应在提供给客户端之前必须重新向服务器验证。类似no-cache |
响应 | proxy-revalidate | 共享的缓存在提供给客户端之前必须重新向原始服务器验证; 私有的缓存可以忽略这条指令 |
响应 | max-age | 指定文档可以被缓存的时间以及新鲜度的最长时间 |
响应 | s-max-age | 指定文档作为共享缓存时的最长使用时间(若有max-age指令,则以本指令为准); 私有的缓存可以忽略本指令 |
举一个用在HTTP请求 例子,若你在浏览器中按Ctl + F5(强制刷新),通过抓包,则可以发现浏览器发送的请求包含如下的请求头:
Cache-Control : no-cache
Pragma: no-cache