跳到主要内容

3. 在缓存中存储响应

除非满足以下全部条件, 否则缓存 MUST NOT 存储对任何请求的响应:

  • 缓存理解该请求方法, 且该方法被定义为可缓存, 并且

  • 缓存理解该响应状态码, 并且

  • 请求或响应头字段中不出现 "no-store" 缓存指令 (见第 5.2 节), 并且

  • 如果缓存是共享缓存, 响应中不出现 "private" 响应指令 (见第 5.2.2.6 节), 并且

  • 如果缓存是共享缓存, 请求中不出现 Authorization 头字段 (见 [RFC7235] 第 4.2 节), 除非响应明确允许 (见第 3.2 节), 并且

  • 响应满足以下任一条件:

    • 包含 Expires 头字段 (见第 5.3 节), 或

    • 包含 max-age 响应指令 (见第 5.2.2.8 节), 或

    • 包含 s-maxage 响应指令 (见第 5.2.2.9 节) 且该缓存是共享缓存, 或

    • 包含允许其被缓存的缓存控制扩展 (Cache Control Extension) (见第 5.2.3 节), 或

    • 其状态码被定义为默认可缓存 (见第 4.2.2 节), 或

    • 包含 public 响应指令 (见第 5.2.2.5 节).

注意, 上述任何要求都可以被缓存控制扩展覆盖; 见第 5.2.3 节.

在此语境下, 如果缓存能够识别某个请求方法或响应状态码, 并实现所有规定的缓存相关行为, 则称该缓存"理解"了它.

注意, 在正常运行中, 某些缓存不会存储既没有缓存验证器 (cache validator) 也没有显式过期时间的响应, 因为此类响应通常不值得存储. 不过, 并不禁止缓存存储此类响应.

3.1. 存储不完整响应​

当消息帧 ([RFC7230]) 所指示的所有八位组 (octet) 在连接关闭之前被接收时, 才认为响应消息是完整的. 如果请求方法是 GET, 响应状态码是 200 (OK), 并且整个响应头部分已被接收, 那么只要缓存条目被记录为不完整, 缓存 MAY 存储不完整的响应消息体. 同样, 206 (Partial Content) 响应 MAY 像不完整的 200 (OK) 缓存条目那样被存储. 但是, 如果缓存不支持 Range 和 Content-Range 头字段, 或者不理解这些字段中使用的范围单位 (range unit), 则它 MUST NOT 存储不完整或部分内容响应.

缓存 MAY 通过发起后续的范围请求 ([RFC7233]) 并将成功的响应与已存储条目合并 (如第 3.3 节所定义) 来补全已存储的不完整响应. 除非响应已被补全, 或者请求是部分请求且其指定的范围完全位于该不完整响应之内, 否则缓存 MUST NOT 使用不完整响应来应答请求. 缓存 MUST NOT 在未使用 206 (Partial Content) 状态码明确标记的情况下, 向客户端发送部分响应.

3.2. 存储对已认证请求的响应​

除非响应中存在允许存储此类响应的缓存指令, 否则共享缓存 MUST NOT 使用对带有 Authorization 头字段 ([RFC7235] 第 4.2 节) 的请求的缓存响应, 来满足任何后续请求.

在本规范中, 以下 Cache-Control 响应指令 (第 5.2.2 节) 具有该效果: must-revalidate、public 和 s-maxage.

注意, 包含 "must-revalidate" 和/或 "s-maxage" 响应指令的缓存响应, 不允许被共享缓存以过期 (stale) 状态提供 (第 4.2.4 节). 特别是, 带有 "max-age=0, must-revalidate" 或 "s-maxage=0" 的响应, 在源服务器上重新验证之前, 不能用于满足后续请求.

3.3. 组合部分内容​

如果连接过早关闭, 或者请求使用了一个或多个 Range 说明符 ([RFC7233]), 则响应可能只传输了部分表示. 经过若干次此类传输后, 缓存可能已经收到同一表示的多个范围. 如果这些范围都共享同一个强验证器 (strong validator), 并且缓存遵守 [RFC7233] 第 4.3 节中的客户端要求, 那么缓存 MAY 将这些范围组合成单个已存储响应, 并重用该响应来满足后续请求.

在将新响应与一或多个已存储响应组合时, 缓存 MUST:

  • 删除已存储响应中所有 warn-code 为 1xx 的 Warning 头字段 (见第 5.5 节);

  • 保留已存储响应中所有 warn-code 为 2xx 的 Warning 头字段; 并且,

  • 使用新响应中提供的其他头字段 (Content-Range 除外), 替换已存储响应中相应头字段的所有实例.