7.6 控制缓存的能力

服务器可以通过 HTTP 定义的几种方式来指定在文档过期之前可以将其缓存多长时间,按照优先级递减的顺序:

  • 附加一个 Cache-Control: no-store 首部到响应中去;
  • 附加一个 Cache-Control: no-cache 首部到响应中去;
  • 附加一个 Cache-Control: must-revalidate 首部到响应中去;
  • 附加一个 Cache-Control: max-age 首部到响应中去;
  • 附加一个 Expires 日期首部到响应中去;
  • 不附加过期信息,让缓存确定自己的过期日期。

1. no-Store 与 no-Cache 响应首部

  • HTTP/1.1 提供了几种限制对象缓存,或限制提供已缓存对象的方式,以维持对象的新鲜度。no-store 首部和 no-cache 首部可以防止缓存提供未经证实的已缓存对象:
Pragma: no-cache 
Cache-Control: no-store 
Cache-Control: no-cache
  • 标识为 no-store 的响应:禁止缓存对响应进行复制。缓存通常会像非缓存代理服务器一样,向客户端转发一条 no-store 响应,然后删除对象。
  • 标识为 no-cache 的响应:实际上是可以存储在本地缓存区中的。只是在与原始服务器进行新鲜度再验证之前,缓存不能将其提供给客户端使用。这个首部使用 do- not-serve-from-cache-without-revalidation 这个名字会更恰当一些。
  • HTTP/1.1 中提供 Pragma: no-cache 首部是为了兼容于 HTTP/1.0+。除了与只理解 Pragma: no-cache 的 HTTP/1.0 应用程序进行交互时,HTTP 1.1 应用程序都应该使用 Cache-Control: no-cache。
  • 从技术上来讲,Pragma:no-cache 首部只能用于 HTTP 请求,但在实际中它作为扩展首部已被广泛地用于 HTTP 请求和响应之中。

2. must-revalidate 响应首部

  • 可以配置缓存,使其提供一些陈旧(过期)的对象,以提高性能。
  • 但是,如果原始服务器希望缓存严格遵守过期信息,可以在原始响应中附加一个 Cache-Control: must-revalidate 首部。
  • 该响应首部告诉缓存,在事先没有跟原始服务器进行再验证的情况下,不能提供这个对象的陈旧副本。缓存仍然可以随意提供新鲜的副本。如果在缓存进行 must-revalidate 新鲜度检查时,原始服务器不可用,缓存就必须返回一条 504 Gateway Timeout 错误。

3. max-age 响应首部

  • 表示的是从服务器将文档传来之时起,可以认为此文档处于新鲜状态的秒数。
  • 还有一个 s-maxage 首部,其行为与 max-age 类似,但仅适用于共享(公有)缓存:
    Cache-Control: max-age=3600
    Cache-Control: s-maxage=3600
  • 服务器可以请求缓存不要缓存文档,或者将最大使用期设置为零,从而在每次访问的时候都进行刷新:
    Cache-Control: max-age=0
    Cache-Control: s-maxage=0

4. Expires 响应首部

  • 不推荐使用 Expires 首部,它指定的是实际的过期日期而不是秒数。
  • 由于很多服务器的时钟都不同步,或者不正确,所以最好还是用剩余秒数,而不是绝对时间来表示过期时间。
  • 有些服务器还会回送一个 Expires:0 响应首部,试图将文档置于永远过期的状态,但这种语法是非法的,可能给某些软件带来问题。应该试着支持这种结构的输入,但不应该产生这种结构的输出。

5. 试探性过期

  • 如果响应中没有 Cache-Control: max-age 首部,也没有 Expires 首部,缓存可以计算出一个试探性最大使用期。
  • 可以使用任意算法,但如果得到的最大使用期大于 24 小时,就应该向响应首部添加一个 Heuristic Expiration Warning(试探性过期警告,警告 13)首部。
  • LM-Factor 算法是一种很常用的试探性过期算法,如果文档中包含了最后修改日期,就可以使用这种算法。LM-Factor 算法将最后修改日期作为依据,来估计文档有多么易变。算法的逻辑如下所示:
    • 如果已缓存文档最后一次修改发生在很久以前,它可能会是一份稳定的文档,不太会突然发生变化,因此将其继续保存在缓存中会比较安全。
    • 如果已缓存文挡最近被修改过,就说明它很可能会频繁地发生变化,因此在与服务器进行再验证之前,只应该将其缓存很短一段时间。
  • 实际的 LM-Factor 算法会计算缓存与服务器对话的时间跟服务器声明文档最后被修改的时间之间的差值,取这个间隔时间的一部分,将其作为缓存中的新鲜度持续时间。下图给出了 LM-factor 的新鲜周期。图中用交叉线画出的阴影表示的是将 LM-factor 设置为 0.2 计算出的新鲜周期。
    这里写图片描述
  • 通常人们会为试探性新鲜周期设置上限,这样它们就不会变得太大了。尽管比较保守的站点会将这个值设置为一天,但通常站点会将其设置为一周。
  • 如果最后修改日期也没有的话,缓存就没什么信息可利用了。缓存通常会为没有任何新鲜周期线索的文档分配一个默认的新鲜周期(通常是一个小时或一天)。有时,比较保守的缓存会将这种试探性新鲜生存期设置为 0,强制缓存在每次将其提供给客户端之前,都去验证一下这些数据仍然是新鲜的。
  • 试探性新鲜度计算可能比你想象的要常见得多。很多原始服务器仍然不会产生 Expires 和 max-age 首部。选择缓存过期的默认时间时要特别小心!

6. 客户端的新鲜度限制

  • Web 浏览器都有 Refresh(刷新)或 Reload(重载)按钮,可以强制对浏览器或代理缓存中可能过期的内容进行刷新。
  • Refresh 按钮会发布一个附加了 Cache-Control 请求首部的 GET 请求,这个请求会强制进行再验证,或者无条件地从服务器获取文档。Refresh 的确切行为取决于特定的浏览器、文档以及拦截缓存的配置。
  • 客户端可以用 Cache-Control 请求首部来强化或放松对过期时间的限制。Cache-Control请求指令:
指令目的
Cache-Control: max-stale
Cache-Control: max-stale = <s>
缓存可以随意提供过期的文件。如果指定了参数 <s>,在这段时间内,文档就不能过期。这条指令放松了缓存的规则
Cache-Control: min-fresh= <s>至少在未来 <s> 秒内文档要保持新鲜。这就使缓存规则更加严格了
Cache-Control: max-age = <s>缓存无法返回缓存时间长于 <s> 秒的文档。这条指令会使缓存规则更加严格,除非同时还发送了 max-stale 指令,在这种情况下,使用期可能会超过其过期时间
Cache-Control: no-cache
Pragma: no-cache
除非资源进行了再验证,否则这个客户端不会接受已缓存的资源
Cache-Control: no-store缓存应该尽快从存储器中删除文档的所有痕迹,因为其中可能会包含敏感信息
Cache-Control: only-if-cached只有当缓存中有副本存在时,客户端才会获取一份副本

7. 注意事项

  • 文档过期系统并不是一个完美的系统。如果发布者不小心分配了一个很久之后的过期日期,在文档过期之前,她要对文档做的任何修改都不一定能显示在所有缓存中。
  • 文档过期采用了“生存时间”技术,这种技术用于很多因特网协议,比如 DNS 中。与 HTTP 一样,如果发布了一个很久之后才到时的过期日期,然后发现需要进行修改,DNS 就会遇到麻烦。但是,与 DNS 不同的是,HTTP 为客户端提供了一些覆盖和强制重载机制。
  • 因此,很多发布者都不会使用很长的过期日期。而且,很多发布者甚至都不使用过期日期,这样缓存就很难确定文档会在多长时间内保持新鲜了。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值