Cache in HTTP/1.1
HTTP 通常用于分布式信息系统,分布式系统可以通过缓存响应来提升性能。
如果不能显著的提升性能,缓存将毫无意义。HTTP/1.1 中缓存的目的就是为了去除很多情况下发送请求的需要,以及很多其他的情况下,发送完整响应的需要。前者减少了很多操作需要的网络 round-trips;我们使用一种 “expiration” 机制来达到此目的。后者减少网络带宽的需求;我们使用一种 “validation” 机制来达到此目的。
有效期机制由缓存直接向请求方返回响应,不必向原始服务器请求。
验证机制在返回响应前,缓存向原始服务器重新验证缓存条目的合法性,消息中仅携带必要的信息,减少网络带宽占用。
性能,可用性,和断开连接操作的需求要求我们能放松关于语义透明性方面的目标。HTTP/1.1 协议允许原始服务器,缓存,和客户端在必要时显式的减少透明性。然而,因为不透明的操作可能使非专业的用户感到困惑,且可能对特定的服务器应用不兼容 (例如那些订购的商品),协议需要降低透明度
- 客户端和原始服务器仅能通过显式的协议层级的请求来降低透明度
- 缓存和客户端降低透明度时需要对终端用户发出显式警告
语义透明性指的是 user agent 在通讯过程中感觉不到缓存的存在,觉得所有响应都来自于原始服务器。
因此,HTTP/1.1 协议提供这些重要元素:
- 当各方都需要时,协议特性能提供完全的语义透明性。
- 协议特性允许原始服务器和用户代理显式地请求和控制不透明的行为。
- 协议特性允许缓存为没有保持所要求的近似语义透明性的响应关联警告。
一个基本的原则是客户端必须能检测到任何对语义透明性的潜在放松。
1.1 Cache Correctness
一个正确的缓存必须用最 up-to-date 的适合请求的响应来响应请求。它满足下述条件:
-
原始服务器重新校验响应操作所返回内容中的等价性检查。
-
它足够“新鲜”。在默认情况下,这意味着它满足客户端,原始服务器和缓存的最低限度的新鲜性需求;如果原始服务器指定,则仅受限于原始服务器的新鲜度需求。
如果存储的响应对客户端和服务器的最高限度的新鲜度需求来说不够“新鲜”,缓存仍有可能返回响应,但响应包含一个合适的 Warning header,除非这样的响应是被禁止的 (e.g.,通过 “no-store” 缓存指令,或通过 “no-cache” 的缓存请求指令)。
-
它是一个合适的 304 (Not Modified),305 (Proxy Redirect),或错误 (4xx 或 5xx) 响应信息。
如果缓存不能与原始服务器通讯,且缓存中的响应能正确提供服务时,正确的缓存应该依据上述条件进行响应,否则,正确的缓存必须返回一个错误或警告以表明通讯失败。
如果缓存接收到一个响应 (无论是一个完整的响应还是一个 304 (Not Modifyed) 响应),该响应通常会转发给请求的客户端,且当收到的响应不再新鲜,缓存应该直接转发它到请求的客户端,不添加新的警告 (也不移除任何现存的警告)。一个缓存不应该尝试重新验证一个响应,仅仅因为它在传输过程中变得不新鲜;这可能会导致一个无限循环。接收到不新鲜的响应且响应不包含 Warning 的用户代理可向用户展示警告提示。
缓存对于到来的响应只能做加法,不能修响应的原语义。
1.2 Warnings
当缓存返回一个既不是一手也不够“新鲜”的响应时,它必须使用 Warning general-header 为该影响关联一个警告。警告允许客户端采取合适的行动。
警告被赋值为 3 位数字警告码。第一位数字表示在成功重新验证后,Warning 能否从存储的缓存条目中删除:
- 1xx 描述响应的新鲜度或重新验证状态的 Warning,在成功重新验证后必须被删除。1xx 警告码可能在缓存验证缓存的条目时产生。它禁止由客户端生成。
- 2xx Warning,描述一些关于 entity body 和 entity header 不会因重新验证而改变的方面。成功重新验证后禁止删除。
110 Response is stale
当返回的响应不新鲜时,包含此警告码
111 Revalidation failed
因无法抵达服务器而导致尝试重新验证响应失败,缓存返回一个不新鲜的响应,包含此警告码
112 Disconnected operation
如果缓存有意与网络的其他部分断开连接一段时间,包含此警告码
113 Heuristic expiration
缓存启发式的选择一个大于 24小时 的新鲜度生命周期,且响应的 Age 大于 24 小时,包含此警告码
199 Miscellaneous warning
警告文本可能包含向人类用户展示或记录日志的任意信息。接收到这一警告的系统不能采取任何自动的行动,除了向用户展示警告。
214 Transformation applied
如果中间缓存或代理应用了一些转换改变了响应或响应的 entity body 中的 content-coding (在 Content-Encoding header 中指定) 或 media-type (在 Content-Type header 中指定),除非此 Warning code已经出现在响应中,添加此响应码。
299 Miscellaneous persistent warning
警告文本可能包含向人类用户展示或记录日志的任意信息。接收到这一警告的系统不能采取任何自动的行动。
HTTP 1.0 缓存会缓存响应中所有的警告,不会删除任何一个第一类警告。传递给 HTTP/1.0 缓存的响应中的 Warning 携带一个额外的 warning-date 字段,以避免将来的 HTTP/1.1 接收方相信一个错误的缓存 Warning。
Warning 也携带警告文本。文本可能是任何合适的自然语言 (或许基于 Client 的 Accept headers),且包含一个可选的指示表示使用的字符集。
多个警告可能关联到一个响应上 (要么通过原始服务器,要么通过缓存),多个警告有相同的警告码。例如,服务器可能同时使用英语和巴斯克语提供相同的警告。
1.2.1 Warning
Warning general-header 字段被用于携带关于消息的状态或转变的额外信息,这些信息可能在消息内不会反映出来。这一信息通常用于警告可能存在的语义透明性的缺乏,由应用于消息的 entity body 的缓存操作或转换导致。
Warning header 在响应中使用如下格式进行发送:
Warning = "Warning" ":" 1#warning-value
warning-value = warn-code SP warn-agent SP warn-text [SP warn-date]
warn-code = 3DIGIT
warn-agent = ( host [ ":" port ] ) | pseudonym; 添加到 Warning header 的名字或假名用于调试
warn-text = quoted-string
warn-date = <"> HTTP-date <">
一个响应可能携带超过一个 Warning header。
缓存不允许删除任何接收的消息中的 Warning header。然而,如果缓存成功验证了缓存条目,它应该在关联该条目前,将 Warning header 移除,但某些特定的 Warning codes 除外。随后它必须添加任何从验证的响应中接收到的 Warning headers 。换句话说,Warning header 关联的时最近相关的响应。
当前定义的 warn-codes 的列表如下:
- 110 Response is stale
当返回的响应不新鲜时,必须包含。 - 111 Revalidation failed
如果缓存因为无法到达服务器导致尝试重新验证响应失败,而返回了一个不新鲜的响应,必须包含。 - 112 Disconnected operation
如果缓存有意在一段时间内与剩余的网络断开连接,应该包含。 - 113 Heuristic expiration
如果缓存试探性地选择了一个大于 24 小时的新鲜度生命周期且响应的 age 大于 24 小时,必须包含。 - 199 Miscellaneous warning
警告文本可能包含展现给人类用户的任意信息。接收到这一警告的系统禁止采取任何自动行为,除了向用户展示警告。
1.3 Cache-control Mechanisms
HTTP/1.1 中基础的缓存机制 (服务器特定的过期时间和验证器) 是对缓存的隐式指令。在一些情况下,服务器或客户端可能需要向 HTTP 缓存提供显式指令。为了这一目的,我们使用了 Cache-Control header。
Cache-Control header 允许客户端或服务器在请求或响应中传输各式各样的指令。这些指令通常会覆盖默认的缓存算法。作为一个通用规则,如果 header 值之间有任何明显的冲突,则应用最具限制性的解释 (即,应用最可能保证语义透明性的解释)。然而,在一些情况下,cache-control 指令被显式指定用于削弱语义透明性 (例如,“max-stale” 或 “public”)。
对缓存的显式指令是否添加不同于隐式指令的新机制?还是只是修改隐式指令指定的行为?
1.4 Explicit User Agent Warning
1.5 Exceptions to the Rules and Warnings
1.6 Client-controlled Behavior
当原始服务器 (更小程度上,中间缓存,取决于它们对响应的 age 的贡献) 是过期信息的主要来源,一些情况下,客户端可能需要控制缓存是否不进行验证就返回缓存中的响应。客户端使用几个 Cache-Control header 的指令来做到这一点。
客户端请求能指定其能接受的关于未验证响应的最大 age;指定 0 值强制缓存重新验证所有响应。 客户端也能指定响应过期前最小的留存时间。这两个选项增加了缓存行为的约束,所以不能进一步放宽缓存语义的透明度。
客户端也能指定它愿意接受不新鲜的响应,直到某个不新鲜度的最大数量。这放宽了对缓存的约束,所以可能会破坏原始服务器对语义透明性的约束,但是可能对支持断开连接的行为,或在面对糟糕的连接性时的可用性十分必要。
- 验证缓存中的响应和确定响应过期有何区别?为什么要分开控制?
- 允许接受来自缓存的不新鲜的响应有何影响?
- 削弱语义的透明性作何解释?
2. Expiration Model
2.1 Server-Specified Expiration
当缓存能完全避免向原始服务器发送请求时,HTTP 缓存能工作得最好。避免请求的基本机制是为每个原始服务器提供一个显式的有效期时间,表明该响应在该期限内能满足随后的请求。换句话说,缓存在不是第一次联系服务器的情况下能返回一个新鲜的响应。
我们期望服务器会给响应赋值一个未来的有效期时间,并确信在该有效期时间到达前,entity 在语义上不会发生改变。只要服务器小心的选择有效期时间,通常就能保证语义透明性。
如果原始服务器期望强制一个语义透明的缓存验证每个请求,它可能赋予一个过去的显式有效期时间。这意味着响应总是不新鲜的,在处理随后的请求时,缓存应该先进行验证,才能使用该响应。
如果原始服务器期望强制任一 HTTP/1.1 缓存,无论它是如何配置的,验证每一个请求,它应该使用 “must-revalidate” 缓存控制指令。
服务器使用 Expires header 或 Cache-Control header 的 max-age 指令来指定显式有效期时间。
有效期时间不能被用于强制 user agent 刷新它的显示或重新加载资源;它的语义仅应用于缓存机制,且缓存机制仅在对某资源的新请求被初始化时,检测该资源的有效期状态。
2.2 Heuristic Expiration
因为原始服务器并不是总是提供显式过期时间,HTTP 缓存通常给予一个启发式的有效期时间,应用使用其他 header 值(例如 Last-Modified time)的算法来估计一个近似合理的有效期时间。HTTP/1.1 规范没有提供没有提供指定的算法,但是施加了对结果的最糟糕情况下的约束。因为启发式有效期时间可能会对语义透明性做出妥协,它们应该被谨慎使用,我们鼓励原始服务器尽可能地提供显式有效期时间。
2.3 Age Calculations
为了知道是否缓存的条目是否是最新的,缓存需要知道是否条目的年龄是否超过它的新鲜度生命周期。
在此讨论中,我们使用 “now” 表示主机执行运算时的当前时钟值。使用 HTTP 的主机,特别是运行原始服务器和缓存的主机,应该使用 NTP 或一些类似的协议来同步时钟到全球精确时钟标准。
HTTP/1.1 需要原始服务器发送一个 Date header,如果可能的话,对每个响应都是如此,以给出每个响应生成的时间。我们使用术语 “date_value” 来表示 Date header 的值,以一种适合算术操作的形式。
HTTP/1.1 使用 Age response header 来表示传输响应消息从缓存中获取时,其 age 的估算。Age 字段值是自响应被原始服务器生成或重新验证起,缓存对其的时间估计。
本质上,Age 值是资源存在于自原始服务器起延路径上的缓存中的时间,加上在网络中传输消耗的时间。
我们使用术语 “age_value” 来表示 Age header 的值,以一种适合算术操作的形式。
响应的 age 能以两种完全独立的方式计算:
- now 减去 date_value,如果本地时钟与原始服务器时钟同步的很好。如果结果是负数,结果替换为 0。
- age_value,如果所有延响应路径的缓存都实现了 HTTP/1.1。
考虑到在收到响应时,我们有两种独立的方法来计算它的 age,我们可以将它们结合起来
connected_received_age = max(now - date_value, age_value)
只要我们有同步锁或者所有都满足 HTTP/1.1 的路径,其中一个就能获取一个可靠的结果。
因为网络造成的延迟,在服务器产生响应的时间和在下一个缓存或客户端接收到该响应的时间之间会有一些显著的延迟。如果不修正,延迟将造成不合适的低 ages。
因为导致返回 Age 值得请求的初始化必须先于 Age 值得生成,我们可以通过记录请求被初始化的时间来纠正网络延迟。那么,当 Age 值被接收时,它必须被解释为相对于请求被初始化的时间,而不是响应被接收的时间。这一算法导致保守的行为,无论它经历了多少延迟。所有,我们计算:
connect_initial_age = corrected_recevied_age + (now - request_time)
其中 “request time” 是引发响应的请求发送的时间 (根据本地时钟)。
age 计算算法的总结,当缓存接收响应时:
- age_value:Age 的值,Age 是缓存接收的响应中的 header
- date_value:原始服务器的 Date 的值
- request_time:缓存发起导致该缓存响应的请求的 (本地) 时间
- response_time:当缓存接收到响应时的 (本地) 时间
- now:当前的 (本地) 时间。
apparent_age= max(0, response_time - date_value);
corrected_recevied_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;
一个缓存条目的 current_age 通过将 corrected_initial_age 和自缓存条目最后一次被原始服务器验证起过去的时间相加来计算得出。当响应从缓存条目中生成,缓存必须在响应中包含一个 Age header 字段,其值等价于缓存条目的 current_age。
响应中存在 Age header 字段暗示响应不是 first-hand 的。然而,反过来也不对,响应中缺乏 Age header 字段也并非暗示响应是 first-hand 的,除非沿请求路径的所有缓存都符合 HTTP/1.1(i.e.,更老的 HTTP 缓存没有实现 Age header 字段)。
Age 的计算采取保策略,可用性第一,准确性第二,保证在任何时候都能有一个可用的 Age,它可能不是一个完全准确的值。
2.4 Expiration Calculations
为了决定响应新鲜与否,我们需要比较新鲜度生命周期和它的 Age。
我们使用术语 “expries_value” 来表示 Expires header 的值,使用术语 “max_age_value” 来表示响应中 Cache-Control header 的指令 “max-age” 所携带的秒数值。
max-age 指令优先于 Expires,所以如果 max-age 出现在响应中,计算十分简单:
freshness_lifetime = max_age_value
否则,如果 Expires 存在于响应中,计算为:
fressness_lifetime = expires_value - date_value
注意这两种计算方法都不易受时钟偏离影响,因为所有的信息都来自于原始服务器。
如果 Expires,Cache-Control:max-age,或 Cache-Control:s-maxage 都没有在响应中出现,且响应中不包含对缓存的其他约束,缓存可能使用启发式方法计算新鲜度生命周期。缓存必须关联 113 警告到任一 age 大于 24 小时的响应上,如果这样的响应还没有被添加。
如果响应确实有 Last-Modified 时间,启发式有效期值不应该超过自那时起时间间隔的部分。通常因子被设置为 10%。
决定响应是否过期的计算也十分简单:
response_if_fresh = (freshness_lifetime > current_age)
2.5 Disambiguating Expiration values
因为有效期值的赋值十分乐观,所以两个缓存包含对相同资源的不同的新鲜值。
如果执行检索的客户端接收一个 non-first-hand 的响应,该响应在其缓存中已经是新鲜的了且现存缓存条目中的 Date header 比新的响应中的 Date 要新,client 可能会忽略该响应。如果是这样,它可能使用 “Cache-Control: max-age=0” 指令重试请求,来强制原始服务器进行检擦。
如果缓存有两个新鲜的响应来自相同的 representation,但是有不同的验证器,缓存必须使用 Date header 更近的响应。这一情况可能在缓存从其他缓存接收响应时出现,或者客户端请求重新加载或重新验证一个显然新鲜的缓存条目。
2.6 Disambiguating Multiple Response
因为客户端可能从多条路径接收响应,所以一些响应经过某个缓存集合,其他响应经过其他不同的缓存集合,客户端可能以不同于原始服务器发送响应的顺序接收到响应。客户端推荐使用最近生成的响应,即使旧的响应依然明显新鲜。
entity tag 和 expiration 值都不能强加响应的顺序,因为可能更新的响应有意的携带更早的有效期时间。Date 值以一秒为单位进行排序。
当客户端尝试重新验证缓存条目,且接收的响应包含 Date header 指出该响应比现存的缓存条目更旧,那么客户端应该无条件的重复该请求,并包含
Cache-Control: max-age=0
来强制中间缓存向原始服务器直接验证它们的拷贝,或
Cache-Control: no-cache
来强制任何中间缓存从原始服务器获取新的拷贝。
如果 Date 值相等,客户端能使用任一响应(或者,更慎重的话,请求新的响应)。服务器不能依赖客户端能在同一秒生成的响应中做出确定选择,如果响应的有效期时间重叠。
3. Validation Model
当缓存中有一条不新鲜的条目,想要被用作对客户端请求的响应,它首先必须由原始服务器 (或可能是有新鲜响应的缓存) 检验以确定缓存的条目是否可用。我们称之为 “validating” 缓存条目。如果缓存的条目是好的,我们不想支付重新传输完整响应的开销,如果缓存条目是非法的,我们也不想支付额外的往返旅途的开销,HTTP/1.1 协议支持有条件的方法的使用。
支持有条件查询的关键协议特点涉及 “cache validators”。当原始服务器生成一个完全响应,它会为它关联一些验证器,保存在缓存条目中。当客户端 (用户代理或代理缓存) 向存在缓存条目的某资源发送一个有条件的请求时,请求包含相关的验证器。
服务器随后检查当前 entity 相关的验证器和请求中的验证器,且,如果它们匹配,服务器返回一个特殊的状态码 (通常,304 (Not Modified)) 且不返回 entity body。否则,服务器返回一个完整的响应 (包含 entity body)。因此,如果验证器匹配,我们避免了传输完整的响应,如果不匹配,我们避免了额外的往返回路。
在 HTTP/1.1 中,对某资源的条件请求看上去与普通的请求完全相同,除了它携带一个特殊的 header (包含一个验证器),隐式的将方法 (通常为 GET) 转变为条件的。
协议对缓存验证条件有正面和反面的响应。即对请求来说仅当验证器匹配时方法执行,或仅当验证器不匹配时,方法被执行。
注意:缺乏验证器的响应可能仍然能被缓存,且在其过期前提供服务,除非被 cache-control 指令显式禁止。然而,如果缓存中的 entity 没有验证器,缓存不能对它做有条件的检索,这意味着在它过期后它不能被刷新。
3.1 Last-Modified Dates
Last-Modified entity-header 字段值通常被用作缓存的验证器。简而言之,如果缓存条目自 Last-Modified 值之后没有被修改,则认为该缓存条目是合法的。
3.2 Entity Tag Cache Validators
ETag response-header 字段值,一个 entity tag,为 “opaque” 的缓存验证器提供。在不方便存储修改的日期的情况下,它可能能提供更可靠的验证,比如在 HTTP 日期不能提供 1s 的分辨率时,或原始服务器期望避免使用修改日期可能造成的悖论。
Entity tags 被用于比较两个或多个来自同一请求资源的 entities。HTTP/1.1 在 ETag,If-Match,If-None-Match 和 If-Range header 字段中使用 entity tags。
一个 “strong entity tag” 仅当两个表示同一资源的 entities 的八位表示完全等价时,才能被它们共享。
一个 “weak entity tag”,由 “W/” 前缀表示,仅当 entities 是等价的,相互替换时语义上不会有显著改变时,能被这两个 entities 共享。若实体标记仅能用于弱比较。
entity tag 在关联某特定资源的所有 entities 的所有版本中必须唯一。所给的 entity tag 值可能被用于对不同 URIs 的请求中包含的 entities。对不同 URIs 的请求中的 entities 使用相同的 entity tag value 并不意味着这些 entity 是等价的。
3.3 Weak and Strong Validators
原始服务器和代理通过比较验证器来确定它们表示的是否是同一 entity。一般来说,我们期望当 entity (entity body 和 entity headers) 改变时,其对应的验证器也随之改变。这种情况下,我们称此验证器为 “strong validator”。
然而,有些情况下,服务器倾向于当 entity 的语义发生显著改变时,才改变验证器,如果 entity 的改变微不足道,则不改变验证器。验证器不随资源时刻改变,则称之为 “weak validator”。
Entity tag 通常是 “strong validator”,但是协议提供方法可以将 entity tag 标识为 “weak”。如果 entity 的某位发生变化,entity tag 也发生变化,则认为它是 “strong validator”;如果 entity 的含义发生变化,entity tag 才发生变化,则认为它是 “weak validator”。“strong validator” 可以认为是某 entity 的标识符的一部分,“weak validator” 可以认为是语义上等价的 entity 集合的标识符的一部分。
注意:
“strong validator” 的一个例子是,当 entity 每次发生改变时,递增的一个整数。
“weak validator” 的一个例子是,entity 发生改变的时间,具有秒解析度。在一秒内,entity 可能发生多次改变。
对 “weak validator” 的支持是可选的,但是 “weak validator” 能提高等价对象缓存的效率。比如,某网站的点击计数器每隔几天或一周更新一次就足够了,对于这一间隔期间的值我们可以认为它们是等价的。
验证器的使用要么是在客户端生成一个在验证 header 中包含验证器的请求时,要么是在服务器比较两个验证器时。
一个 Last-Modified 时间,当作为请求中的验证器时,是隐式 weak 的,除非它能被推断为 strong,使用下述规则:
- 原始服务器比较验证器和 entity 当前的验证器,且
- 原始服务器清楚的知道关联的 entity 没有在当前验证器覆盖的那秒改变两次。
或
- 客户端在 If-Modified-Since 或 If-Unmodified-Since header 中使用验证器,因为客户端有相关 entity 的缓存条目,且
- 缓存条目包含 Date 值,它给出原始服务器发送原始响应的时间,且
- Last-Modified 时间至少在 Date 值前 60 秒。
或
- 中间缓存比较验证器和其缓存条目中 entity 包含的验证器,且
- 缓存条目包含 Date 值,给出原始服务器发送原始响应的时间,且
- Last-Modified 时间至少在 Date 值前 60 秒。
这一方法依赖于一个事实,如果原始服务器在同一秒发送了两个不同的响应,至少有一个响应其 Date 与 Last-Modified 值相同。60s 的限制防止 Date 和 Last-Modified 值由不同的时钟产生,或在准备响应过程中的不同时刻生成。
服务器同一秒发送的两个响应中,逻辑上至少有一个响应其 Date 与 Last-Modified 值相同,否则两个响应的 entity 应该完全相同,
或者说对同一请求的响应完全相同,因为 entity 在发送响应前被修改, Last-Modified 值一定相同。
60s 的限制一定程度上防止 Date 和 Last-Modified 值由不同的时钟产生,比如 Last-Modified 的值大于 Date;
防止 Date 和 Last-Modified 值在准备响应过程中的不同时刻生成,潜在条件是准备响应过程不需要 60s,这样保证了在准备响应过
程中 entity 不会发生改变。
3.4 Rules for When to Use Entity Tags and Last-Modified Dates
HTTP/1.1 原始服务器:
- 应该发送 entity tag 验证器除非办不到。
- 可能发送 weak entity tag 而不是 strong entity tag,如果给予性能的考虑支持使用 weak entity tags 或不能发送 strong entity tag。
- 如果能发送的话,应该发送 Last-Modified 值。在 If-Modified-Since header 中使用这一 date 会导致严重问题,有破坏语义透明度的风险,此种情况下不发送。
换句话说,HTTP/1.1 原始服务器偏向的行为是发送 strong entity tag 和 Last-Modified 值。
HTTP/1.1 客户端:
- 如果原始服务器提供了一个 entity tag,必须在任何 cache-conditional 请求中使用这个 entity tag (使用 If-Match 或 If-None-Match)。
- 如果原始服务器仅提供 Last-Modified 值,应该在 non-subrange cache-conditional 请求中使用该值 (using If-Modified-Since)。
Cache-Control
Cache-Control general-header 字段被用于指定指令,沿请求/响应链的所有缓存机制都必须遵循这一指令。指令指定的行为用于防止缓存对请求和响应产生不利的影响。这些指令通常会重载缓存算法的默认行为。缓存指令是单向的,请求中存在指令并不意味着响应中也会有相同的指令。
代理和网关必须传递缓存指令,不管指令对应用有何意义,因为指令能被应用到沿请求/响应链的所有接收方。为某个特定的缓存指定特定的缓存指令是不可能的。
Cache-Control = "Cache-Cotrol" ":" 1#cache-directive
Range
1. Byte Ranges
因为所有的 HTTP entities 在 HTTP 消息中都以字节序列表示,对任一 HTTP entity 来说,byte range 的概念都是有意义的。
HTTP 中的 byte range 规范应用于 entity-body 中的字节序列。
byte range 操作能指定单个字节范围,或单个 entity 中范围的集合。
ranges-specifier = byte-ranges-specifier
byte-ranges-specifier = bytes-unit "=" byte-range-set
byte-range-set = 1#( byte-range-spec | suffix-byte-range-spec )
byte-range-spec = first-byte-pos "-" [last-byte-pos]
first-byte-pos = 1*DIGIT
last-byte-pos = 1*DIGIT