HTTP Cache功能分析总结

举报
yd_245546638 发表于 2022/10/27 16:49:33 2022/10/27
【摘要】 HTTP Cache功能分析总结[分析范围限制]private, non-share, proxy cache以及cache-extension在本文中不作详细分析。1      Cache功能描述HTTP Cache的根本作用是提高HTTP的性能。Cache通过减少向网络发送请求的次数,减少发送完整响应消息的次数达到提高性能、减小网络带宽利用的目的。HTTP/1.1 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%

       如果响应消息中不带expirescache-control: max-agecache-control: s-maxage,也没有last-modifiedW3C中使用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附件


 

 

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。