HTTP Cache功能分析总结
HTTP Cache功能分析总结
[分析范围限制]
private, non-share, proxy cache以及cache-extension在本文中不作详细分析。
1 Cache功能描述
HTTP Cache的根本作用是提高HTTP的性能。Cache通过减少向网络发送请求的次数,减少发送完整响应消息的次数达到提高性能、减小网络带宽利用的目的。
HTTP/1.1 Cache的重要特征:
- 提供语义透明性,即对用户来说,Cache可以是透明的。
- 允许user agent和origin server的非透明请求和操作。
- 可以在响应之后添加warnings头域(收到不够fresh的非first-hand消息)。
HTTP Cache中保存的必须是最新的响应的资源。理论情况下,从Cache缓存中取到的消息与从服务器上收到的消息是相同的。
2 Cache机制
Cache机制的基本原则:服务端指定超时时间、进行有效性校验。在HTTP/1.1中使用Cache-Control头域来表达,Cache-Control directives尽量保持语义透明性,当消息不满足语义透明性时(例如获取到的资源已经超时),需要明确通知用户(添加warnings,例如取用超时的响应消息,必须(MUST)在响应消息中添加一个110(Response is stale)的warnings)。
Warnings有两类:
- 1xx 描述缓存的消息是否新、重校验的状态等。当重校验成功时,1xx必须被删除。
- 2xx 描述消息体或者消息头已经变化,内容与origin server上的消息不同。
3 头域说明
Cache-Control定义与说明:
Cache-Control = "Cache-Control" ":" 1#cache-directive
cache-directive = cache-request-directive
| cache-response-directive
cache-request-directive =
"no-cache" ; Section 14.9.1
| "no-store" ; Section 14.9.2
| "max-age" "=" delta-seconds ; Section 14.9.3, 14.9.4
| "max-stale" [ "=" delta-seconds ] ; Section 14.9.3
| "min-fresh" "=" delta-seconds ; Section 14.9.3
| "no-transform" ; Section 14.9.5
| "only-if-cached" ; Section 14.9.4
| cache-extension ; Section 14.9.6
cache-response-directive =
"public" ; Section 14.9.1
| "private" [ "=" <"> 1#field-name <"> ] ; Section 14.9.1
| "no-cache" [ "=" <"> 1#field-name <"> ]; Section 14.9.1
| "no-store" ; Section 14.9.2
| "no-transform" ; Section 14.9.5
| "must-revalidate" ; Section 14.9.4
| "proxy-revalidate" ; Section 14.9.4
| "max-age" "=" delta-seconds ; Section 14.9.3
| "s-maxage" "=" delta-seconds ; Section 14.9.3
| cache-extension ; Section 14.9.6
cache-extension = token [ "=" ( token | quoted-string ) ]
- public
所有的cache都可以缓存的消息。
- private
只有特定用户才能缓存的消息,其它用户不能缓存。
- no-cache
如果没有指定任何头域,整个响应可以缓存,但是不能直接给后续请求使用(除非到服务端进行了重校验)。
如果指定了一些头域,这些头域需要到服务端重校验后才能报给用户。
- no-store
不允许缓存相关消息。
- max-age,
在用户没有指定max-stale时,cache返回的响应消息的age必须小于max-age所指定的值。如果请求消息和cache中都存在max-age,以较小的值为准。max-age=0表示强制从服务端取消息。
- s-maxage
与max-age差不多,该directive在share cache中使用,优先级高于max-age, expires。
- min-fresh
满足条件freshness_lifetime >= age + min_fresh_value的缓存消息符合要求。
- max-stale
如果没有指定max_stale_value,任何age的缓存都可以直接取用。
如果指定了max_stale_value,在expires_value + max_stale_value时间范围内的消息可以取用。
- only-if-cached
可以直接从cache中取出的消息使用。
- must-revalidate
必须到服务端进行重校验。
- no-transform
不能修改以下头域
- Content-Encoding
- Content-Range
- Content-Type
详细说明及其它头域描述请参考RFC2616协议文档。
4 Cache相关计算
- age计算方法
客户端可通过指定max-age来指定最大可接受、无须校验的资源,通过指定该值为zero来强制校验。服务端指定资源超时的时间(使用expires头域、或cache-control中的max-age directive、或使用启发式超时时间(last-modified)),超时前客户端可直接取用非first-hand资源。服务端可通过指定超时时间为过去的某个时间来强制资源校验。如果服务端要求所有cache对其资源都需要校验,则带上“must-revalidate” cache-control directive。
HTTP使用age来表示资源在cache中缓存的时长,age有两种独立的计算方法。
- 如果本端时间与服务器时间基本同步,使用当前时间减去Date的值(负数用zero代替)。
- 如果是顺从HTTP/1.1的资源,可直接使用age的值。
当两种情况同时存在时使用下面的公式计算结果:
corrected_received_age = max(now - date_value, age_value)
corrected_initial_age = corrected_received_age + (now - request_time)
如果接收到的消息中有age directive,表明这个响应消息一定不是first-hand消息,但是没有age并不代表消息就是一手的(针对非HTTP/1.1的响应消息)。Cache Age的计算方法总结如下:
/*
* age_value
* is the value of Age: header received by the cache with
* this response.
* date_value
* is the value of the origin server's Date: header
* request_time
* is the (local) time when the cache made the request
* that resulted in this cached response
* response_time
* is the (local) time when the cache received the
* response
* now
* is the current (local) time
*/
apparent_age = max(0, response_time - date_value);
corrected_received_age = max(apparent_age, age_value);
response_delay = response_time - request_time;
corrected_initial_age = corrected_received_age + response_delay;
resident_time = now - response_time;
current_age = corrected_initial_age + resident_time;
- lifetime计算方法
当s-maxage directive存在时,直接通过下面的公式计算。
freshness_lifetime = s_maxage_value
当max-age directive存在时,直接通过下面的公式计算。
freshness_lifetime = max_age_value
max-age的优先级高于expires,如果存在max-age,计算lifetime算法如下:
freshness_lifetime = max_age_value
如果不存在max-age,头域中有expires,计算lifetime算法如下:
freshness_lifetime = expires_value - date_value
如果响应消息中不带expires,cache-control: max-age,cache-control: s-maxage,则使用heuristic算法计算lifetime。
freshness_lifetime = (now – last_modified_value) * 10%
如果响应消息中不带expires,cache-control: max-age,cache-control: s-maxage,也没有last-modified,W3C中使用24h作为freshness lifetime,协议规范中没有明确说明。
freshness_lifetime = 24*3600
如果响应消息的age大于24小时,Cache必须添加113 Warning到响应消息中(如果该Warning已经存在则不需要添加)
- 通过freshness lifetime与current age判断响应是否超时
response_is_fresh = (freshness_lifetime > current_age)
如果Client接收到non-first-hand消息,该消息在自已的Cache中存在,且Cache中消息的Date头域中的值比响应消息中的Date值还要新,Cache可以丢弃该消息,再使用"Cache-Control: max-age=0"或者"Cache-Control: no-cache"直接从origin server上取消息。
当存在同一请求的多个fresh响应消息时,选择Date值较新的一个消息,如果Date相等可随便取一个消息,或者从服务器上重新获取。
如果存在多个不同的响应消息(获取消息走的路由可能不一样),Cache选取响应生成时间最新的消息。
- Cache的校验模式
当cache中的响应消息已经超时,cache需要发送条件请求去服务端重校验,如果服务端校验发现消息没有变,回304,否则回完整的响应消息。
没有validator的消息可以Cache,但是超时后不能进行重校验。重校验的头域以下几种:
Last-Modified //弱校验
ETag //强校验
重校验发送的“Last-Modified”的时候至少要比Date小60秒。
如果Client接收到响应消息中有ETag,后续发送条件请求时(If-Match, If-None-Match)必须带ETag。
如果Client接收到响应消息中只有Last-Modified,后续条件请求(If-Modified-Since, If-Unmodified-Since)可用该值。
如果两个头域都存在,后续请求应该都带这些值。
- 判断响应是否需要缓存
如果响应消息中没有任何Cache相关的头域,建议此类消息不缓存。
共享Cache不能缓存带鉴权信息的消息。
状态码为200, 203, 206(如果支持Content-Range才缓存), 300, 301, 410的响应消息可以Cache给后续请求使用,其它状态码的消息在请求消息中没有特别声明情况下("max-age", "s-maxage", "must-revalidate", "proxy-revalidate", "public" or "private")不能缓存给后续请求使用。
206响应消息的ETag或者Last-Modified头域与本地Cache中的消息匹配时,可把该消息与Cache中的消息进行合并。
Cache缓存消息时必须删除Hop-by-Hop头域。
- Connection
- Keep-Alive
- Proxy-Authenticate
- Proxy-Authorization
- TE
- Trailers
- Transfer-Encoding
- Upgrade
还必须删除1xx的Warning消息,对于2xx的Warining需要带在构造的响应消息中。304,206响应消息中的End-To-End头域必须替换从Cache中取出的消息的这些头域,同时把这些头域更新到Cache中。304响应消息需要转为200消息报给用户。
如果Cache中的数据不完整,又需要报给用户时,必须在响应状态码中标明是206。
接收到5XX响应时,Cache可以(MAY)使用以下两种方式的任一种:
- 直接把该消息转Client,不做任何处理。
- 如果cache-control中没有带"must-revalidate",可以把Cache中以前的消息报给用户。
GET、HEAD请求的相对URI中带"?"时(Query-URI),如果服务端没有提供明确有超时时间,不能Cache该消息(SHOULD,这个与应用相关,即查询URI尽量向服务端请求)。
PUT、DELETE、POST方法对应的操作尽量不涉及Cache。
5 Cache处理逻辑
- 请求合法性
如果请求消息中包含了no-cache directive,不应该(SHOUT NOT)再包含min-fresh,max-stale,max-age等directive。
- cache中的消息是否超时存在两个方面含义
- cache缓存中的消息自身是否已经超时。
- 该缓存消息是否符合用户请求中对cache的限制条件。
当请求与响应中都有max-age时
max_age_value = min(req_max_age_value, rsp_max_age_value)
- 根据directive优先级检查消息是否超时
- 检查请求消息:no-cache --> no-store --> only-if-cached --> max-age --> min-fresh --> max-stale(must-revalidate) --> default
- 检查响应消息:s-maxage --> max-age --> expires & date --> last-modified --> default
检查逻辑请参考excel附件
- 点赞
- 收藏
- 关注作者
评论(0)