跳到主要内容

14. 头部字段定义 (Header Field Definitions)

14 头部字段定义 (Header Field Definitions)​

本节定义所有标准 HTTP/1.1 头部字段的语法和语义. 对于实体头部字段, 发送方和接收方既可以指客户端, 也可以指服务器, 具体取决于谁发送和谁接收该实体.

14.1 Accept​

Accept 请求头字段可以用于指定响应可接受的某些媒体类型. Accept 头也可以用来表示请求被特意限制在一小组期望的类型之内, 例如在请求某个内联图像的情况下就是这样.

       Accept         = "Accept" ":"
#( media-range [ accept-params ] )

media-range = ( "*/*"
| ( type "/" "*" )
| ( type "/" subtype )
) *( ";" parameter )
accept-params = ";" "q" "=" qvalue *( accept-extension )
accept-extension = ";" token [ "=" ( token | quoted-string ) ]

星号 "" 字符用于把媒体类型组合成各种范围, 其中 "/" 表示所有媒体类型, 而 "type/" 表示该类型之下的所有子类型. media-range 可以包含适用于该范围的媒体类型参数.

每个 media-range 的后面都可以跟一个或多个 accept-params, 这些参数以用于指示相对质量因子 (quality factor) 的 "q" 参数开头. 第一个 "q" 参数 (如果有的话) 把 media-range 的各个参数与 accept-params 分隔开来. 质量因子允许用户或用户代理 (user agent) 使用 0 到 1 的 qvalue 标度 (第 3.9 节) 来表示对该 media-range 的相对偏好程度. 默认值为 q=1.

注意: 使用 "q" 这个参数名来分隔媒体类型参数与 Accept 扩展参数, 是由历史上的实践所造成的. 虽然这会阻止任何名为 "q" 的媒体类型参数与 media-range 一起使用, 但是, 鉴于 IANA 媒体类型注册表之中没有任何名为 "q" 的参数, 而且 Accept 之中也很少使用媒体类型参数, 所以发生这种情况的可能性被认为不大. 不鼓励未来的媒体类型注册任何名为 "q" 的参数.

对于下面这个示例:

       Accept: audio/*; q=0.2, audio/basic

它应当被解释为: "我更偏好 audio/basic, 但是, 如果任何 audio 类型在质量打了八折之后仍是最佳可用的类型, 那么也可以把它发送给我."

如果请求之中没有 Accept 头字段, 那么就假定客户端接受所有媒体类型. 如果请求之中有 Accept 头字段, 而服务器无法按照合并之后的 Accept 字段值发送可接受的响应, 那么服务器应当发送 406 (Not Acceptable) 响应.

一个更精细的示例是:

       Accept: text/plain; q=0.5, text/html,
text/x-dvi; q=0.8, text/x-c

用文字来表述, 它会被解释为: "text/html 和 text/x-c 是首选的媒体类型; 如果它们不存在, 那么就发送 text/x-dvi 实体; 如果它也不存在, 那么就发送 text/plain 实体."

媒体范围可以被更具体的媒体范围或者具体的媒体类型所覆盖. 如果多个媒体范围都适用于某个给定的类型, 那么最具体的那个引用具有最高的优先级. 例如:

       Accept: text/*, text/html, text/html;level=1, */*

它具有如下优先级:

       1) text/html;level=1
2) text/html
3) text/*
4) */*

与某个给定类型相关联的媒体类型质量因子, 是通过找出匹配该类型并且优先级最高的那个媒体范围来确定的. 例如:

       Accept: text/*;q=0.3, text/html;q=0.7, text/html;level=1,
text/html;level=2;q=0.4, */*;q=0.5

会导致下列这些值被关联起来:

       text/html;level=1         = 1
text/html = 0.7
text/plain = 0.3
image/jpeg = 0.5
text/html;level=2 = 0.4
text/html;level=3 = 0.7

注意: 用户代理可能被预先提供了一组针对某些媒体范围的默认质量值. 然而, 除非该用户代理是一个无法与其他呈现代理 (rendering agents) 交互的封闭系统, 否则这组默认值应当可以由用户进行配置.

14.2 Accept-Charset​

Accept-Charset 请求头字段可以用于指示响应可以接受哪些字符集. 该字段允许那些能够理解更全面的或者专用于特定目的的字符集的客户端, 向一个能够用这些字符集来表示文档的服务器表明这种能力.

      Accept-Charset = "Accept-Charset" ":"
1#( ( charset | "*" )[ ";" "q" "=" qvalue ] )

字符集的取值在第 3.4 节之中描述. 每个 charset 都可以带有一个相关联的质量值, 该值表示用户对该字符集的偏好. 默认值为 q=1. 下面是一个示例:

      Accept-Charset: iso-8859-5, unicode-1-1;q=0.8

特殊值 "" 如果出现在 Accept-Charset 字段之中, 那么它将匹配该字段之中其他位置未曾提及的每一个字符集 (包括 ISO-8859-1 在内). 如果 Accept-Charset 字段之中没有 "", 那么所有未被显式提及的字符集的质量值都为 0, 只有 ISO-8859-1 例外: 如果它没有被显式提及, 那么它的质量值为 1.

如果请求之中没有 Accept-Charset 头, 那么默认的情况是任何字符集都可以接受. 如果请求之中有 Accept-Charset 头, 而服务器无法按照该头发送可接受的响应, 那么服务器应当发送带有 406 (Not Acceptable) 状态码的错误响应, 不过, 发送不可接受的响应也是被允许的.

14.3 Accept-Encoding​

Accept-Encoding 请求头字段与 Accept 类似, 但是它限制的是响应之中可接受的内容编码 (content-codings, 见第 3.5 节).

       Accept-Encoding  = "Accept-Encoding" ":"
1#( codings [ ";" "q" "=" qvalue ] )
codings = ( content-coding | "*" )

它的使用示例有:

       Accept-Encoding: compress, gzip
Accept-Encoding:
Accept-Encoding: *
Accept-Encoding: compress;q=0.5, gzip;q=1.0
Accept-Encoding: gzip;q=1.0, identity; q=0.5, *;q=0

服务器在根据 Accept-Encoding 字段测试某个 content-coding 是否可以接受时, 使用以下这些规则:

  1. 如果该 content-coding 是 Accept-Encoding 字段之中列出的 content-codings 之一, 那么它就是可以接受的, 除非它附带着为 0 的 qvalue. (如第 3.9 节所定义, 为 0 的 qvalue 意味着 "不可接受".)

  2. Accept-Encoding 字段之中的特殊符号 "*" 匹配该头字段之中未被显式列出的任何可用的 content-coding.

  3. 如果多个 content-codings 都是可以接受的, 那么首选其中非零 qvalue 最高的那个可以接受的 content-coding.

  4. "identity" content-coding 总是可以接受的, 除非它因为 Accept-Encoding 字段之中包含 "identity;q=0" 而被明确拒绝, 或者因为该字段包含 "*;q=0" 并且没有显式包含 "identity" content-coding 而被拒绝. 如果 Accept-Encoding 字段值为空, 那么只有 "identity" 编码是可以接受的.

如果请求之中存在 Accept-Encoding 字段, 而服务器无法按照 Accept-Encoding 头发送可接受的响应, 那么服务器应当发送带有 406 (Not Acceptable) 状态码的错误响应.

如果请求之中没有 Accept-Encoding 字段, 那么服务器可以假定客户端会接受任何 content coding. 在这种情况下, 如果 "identity" 是可用的 content-codings 之一, 那么服务器应当使用 "identity" content-coding, 除非它拥有额外的信息, 并且这些信息表明另一种 content-coding 对该客户端来说是有意义的.

注意: 如果请求之中没有包含 Accept-Encoding 字段, 并且 "identity" content-coding 不可用, 那么会优先使用 HTTP/1.0 客户端通常都能理解的那些 content-codings (即 "gzip" 和 "compress"); 一些旧的客户端会不正确地显示用其他 content-codings 发送的消息. 服务器也可能根据它所掌握的关于特定 user-agent 或者客户端的信息来做出这个决定.

注意: 大多数 HTTP/1.0 应用不能识别也不遵守与 content-codings 相关联的 qvalues. 这意味着 qvalues 对 x-gzip 或者 x-compress 不起作用, 并且不允许把它们与 qvalues 一起使用.

14.4 Accept-Language​

Accept-Language 请求头字段与 Accept 类似, 但是它限制的是作为请求的响应而被首选的自然语言的集合. 语言标签 (language tag) 在第 3.10 节之中定义.

       Accept-Language = "Accept-Language" ":"
1#( language-range [ ";" "q" "=" qvalue ] )
language-range = ( ( 1*8ALPHA *( "-" 1*8ALPHA ) ) | "*" )

每个 language-range 都可以带有一个相关联的质量值, 该值表示对该范围所指定的语言的用户偏好程度的估计. 质量值默认为 "q=1". 例如:

       Accept-Language: da, en-gb;q=0.8, en;q=0.7

它意味着: "我偏好丹麦语, 但是我也接受英式英语和其他类型的英语." 如果一个 language-range 与某个 language-tag 完全相等, 或者它与该标签的某个前缀完全相等, 并且紧随该前缀之后的第一个标签字符是 "-", 那么该范围就匹配该语言标签. 特殊范围 "*" 如果出现在 Accept-Language 字段之中, 那么它将匹配该字段之中其他任何范围都没有匹配到的每一个标签.

注意: 使用前缀匹配规则并不意味着语言标签是以这样的方式分配给各种语言的: 只要用户理解带有某个标签的语言, 该用户就一定也理解所有标签以该标签为前缀的语言. 前缀规则只是允许在实际情况确实如此的时候使用前缀标签.

由 Accept-Language 字段分配给某个 language-tag 的语言质量因子, 是该字段中匹配该语言标签的最长 language-range 的质量值. 如果字段中没有任何 language-range 匹配该标签, 则分配的语言质量因子为 0. 如果请求中不存在 Accept-Language 头, 服务器应当假定所有语言都同等可接受. 如果存在 Accept-Language 头, 则所有被分配了大于 0 的质量因子的语言都是可接受的.

在每个请求中都发送带有用户完整语言偏好的 Accept-Language 头, 可能与用户的隐私期望相抵触. 关于这个问题的讨论见第 15.1.4 节.

由于可理解度高度依赖于具体的用户, 建议客户端应用程序把语言偏好选择权交给用户. 如果没有提供这种选择权, 那么请求中禁止给出 Accept-Language 头字段.

注意: 在把语言偏好选择权交给用户时, 我们提醒实现者注意: 用户并不熟悉上文所描述的语言匹配的细节, 因此应当提供适当的指引. 例如, 用户可能会以为, 选择了 "en-gb" 之后, 如果英式英语的文档不可用, 他们将得到任何类型的英语文档. 在这种情况下, 用户代理可以建议用户添加 "en", 以获得最佳匹配行为.

Accept-Language 字段分配给某个 language-tag 的语言质量因子, 是该字段之中匹配该 language-tag 的最长的那个 language-range 的质量值. 如果该字段之中没有任何 language-range 匹配该标签, 那么分配到的语言质量因子为 0. 如果请求之中没有 Accept-Language 头, 那么服务器应当假定所有语言都是同等可接受的. 如果请求之中有 Accept-Language 头, 那么所有被分配了大于 0 的质量因子的语言都是可以接受的.

在每个请求之中都发送带有用户完整语言偏好的 Accept-Language 头, 可能会违背用户对隐私的期望. 关于这个问题的讨论, 请参见第 15.1.4 节.

由于可理解性高度依赖于单个用户, 因此推荐客户端应用程序把语言偏好的选择权提供给用户. 如果没有提供这种选择, 那么请求之中禁止给出 Accept-Language 头字段.

注意: 在把语言偏好的选择权提供给用户的时候, 我们提醒实现者注意这样一个事实: 用户并不熟悉上文所描述的语言匹配方面的种种细节, 因此应当提供适当的指引. 举例来说, 用户可能会以为, 在选择了 "en-gb" 之后, 如果英式英语不可用, 他们将会得到任何类型的英语文档. 在这种情况下, 用户代理可以建议用户添加 "en", 以便获得最佳的匹配行为.

14.5 Accept-Ranges​

Accept-Ranges 响应头字段允许服务器指示它是否接受针对某个资源的范围请求 (range requests):

          Accept-Ranges     = "Accept-Ranges" ":" acceptable-ranges
acceptable-ranges = 1#range-unit | "none"

接受字节范围请求的源服务器可以发送:

          Accept-Ranges: bytes

但是并不是非这样做不可. 即使没有针对所涉及的资源收到过这个头, 客户端也可以生成字节范围请求 (byte-range request). 范围单位 (range units) 在第 3.12 节之中定义.

不接受针对某个资源的任何种类的范围请求的服务器, 可以发送:

          Accept-Ranges: none

以便建议客户端不要尝试范围请求.

14.6 Age​

Age 响应头字段传达发送方对这样的时间长度的估计: 即自响应 (或者它的重新验证) 在源服务器 (origin server) 上生成以来所经过的时间. 如果一个缓存响应的 age 没有超过它的 freshness lifetime, 那么该响应就是 "新鲜的" (fresh). Age 值按照第 13.2.3 节之中的规定来计算.

           Age = "Age" ":" age-value
age-value = delta-seconds

Age 值是非负的十进制整数, 表示以秒为单位的时间.

如果缓存收到一个大于它所能表示的最大正整数的值, 或者它的任何 age 计算发生了溢出, 那么它必须传输一个值为 2147483648 (2^31) 的 Age 头. 包含缓存的 HTTP/1.1 服务器必须在每一个由它自己的缓存所生成的响应之中包含 Age 头字段. 缓存应当使用至少具有 31 位取值范围的算术类型.

14.7 Allow​

Allow 实体头字段 (entity-header field) 列出由 Request-URI 所标识的资源所支持的方法的集合. 这个字段的目的严格限于把与该资源相关联的有效方法告知接收方. 405 (Method Not Allowed) 响应之中必须存在 Allow 头字段.

          Allow   = "Allow" ":" #Method

使用示例:

          Allow: GET, HEAD, PUT

这个字段不能阻止客户端尝试其他的方法. 然而, Allow 头字段值所给出的指示应当被遵循. 实际被允许的方法的集合, 由源服务器在每次请求的时候加以定义.

Allow 头字段可以随 PUT 请求一起提供, 用来建议新建的或者被修改的资源应当支持哪些方法. 服务器并不被要求支持这些方法, 并且应当在响应之中包含一个 Allow 头, 给出实际支持的方法.

代理禁止修改 Allow 头字段, 即使它并不理解其中指定的所有方法, 因为用户代理可能拥有其他与源服务器进行通信的手段.

14.8 Authorization​

希望向服务器认证它自身的用户代理, 通常 (但是不一定) 是在收到 401 响应之后, 会通过在请求之中包含一个 Authorization 请求头字段来做到这一点. Authorization 字段值由 credentials 组成, 这些 credentials 包含用户代理针对所请求资源的 realm 的认证信息.

          Authorization  = "Authorization" ":" credentials

HTTP 访问认证在 "HTTP Authentication: Basic and Digest Access Authentication" [43] 之中描述. 如果一个请求已经被认证并且指定了 realm, 那么同一 credentials 应当对该 realm 之内的所有其他请求都有效 (假定该认证方案本身并不要求其他的行为, 例如 credentials 会根据挑战值而变化, 或者使用了同步的时钟).

当共享缓存 (shared cache, 见第 13.7 节) 收到一个包含 Authorization 字段的请求时, 它禁止把对应的响应作为对任何其他请求的答复返回, 除非下列具体例外之一成立:

  1. 如果响应包含 "s-maxage" cache-control 指令, 那么缓存可以用该响应来答复后续的请求. 但是 (在指定的最大 age 已经过去的情况下) 代理缓存必须先与源服务器重新验证它, 并且要使用来自新请求的请求头, 以便让源服务器能够认证这个新的请求. (这就是 s-maxage 的定义行为.) 如果响应包含 "s-maxage=0", 那么代理在重用它之前必须始终先重新验证它.

  2. 如果响应包含 "must-revalidate" cache-control 指令, 那么缓存可以用该响应来答复后续的请求. 但是如果该响应已经陈旧, 那么所有缓存必须先与源服务器重新验证它, 并且要使用来自新请求的请求头, 以便让源服务器能够认证这个新的请求.

  3. 如果响应包含 "public" cache-control 指令, 那么它就可以作为对任何后续请求的答复返回.

14.9 Cache-Control​

Cache-Control 通用头字段 (general-header field) 用于指定一些指令, 这些指令必须被请求/响应链上的所有缓存机制所遵守. 这些指令规定了一些行为, 它们的意图是防止缓存对请求或者响应产生不利的影响. 这些指令通常会覆盖默认的缓存算法. 缓存指令是单向的: 某个指令出现在请求之中, 并不意味着在响应之中也要给出同样的指令.

请注意, HTTP/1.0 缓存可能没有实现 Cache-Control, 而可能只实现了 Pragma: no-cache (见第 14.32 节).

缓存指令必须被代理或者网关应用透传, 不管这些指令对该应用自身具有什么样的意义, 因为这些指令可能适用于请求/响应链上的所有接收方. 不可能针对某个特定的缓存来指定 cache-directive.

    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 ) ]

当某个指令出现的时候没有带 1#field-name 参数, 那么该指令适用于整个请求或者响应. 当这类指令带着 1#field-name 参数出现的时候, 那么它只适用于所指定的那一个或者多个字段, 而不适用于请求或者响应的其余部分. 这一机制支持可扩展性; HTTP 协议未来版本的实现可能会把这些指令应用于 HTTP/1.1 之中没有定义的头字段.

cache-control 指令可以细分为下面这些一般的类别:

  • 对哪些内容是可缓存的限制; 这类限制只能由源服务器施加.

  • 对缓存可以存储哪些内容的限制; 这类限制既可以由源服务器施加, 也可以由用户代理施加.

  • 对基本过期机制的修改; 这类修改既可以由源服务器施加, 也可以由用户代理施加.

  • 对缓存重新验证和重新加载的控制; 这类控制只能由用户代理施加.

  • 对实体转换的控制.

  • 对缓存系统的扩展.

14.9.1 什么是可缓存的 (What is Cacheable)​

默认情况下, 如果请求方法、请求头字段和响应状态的要求表明某个响应是可缓存的, 那么该响应就是可缓存的. 第 13.4 节总结了这些关于可缓存性的默认规定. 下面的这些 Cache-Control 响应指令允许源服务器覆盖一个响应的默认可缓存性:

public

表示该响应可以由任何缓存来存储, 即使按照通常的情况它是不可缓存的、或者只能在非共享缓存之中缓存的, 也不例外. (更多的细节, 另见 Authorization, 第 14.8 节.)

private

表示响应消息的全部或者一部分是面向单个用户的, 并且禁止被共享缓存 (shared cache) 存储. 这允许源服务器声明: 响应之中被指定的那些部分只面向一个用户, 对于其他用户发出的请求来说, 它们并不是有效的响应. 私有 (非共享) 缓存可以存储该响应.

注意: "private" 一词的这种用法只控制响应可以在哪里被缓存, 它并不能确保消息内容的隐私.

no-cache

如果 no-cache 指令没有指定 field-name, 那么缓存禁止在没有与源服务器成功重新验证的情况下, 使用该响应来满足后续的请求. 这允许源服务器阻止缓存行为, 即便是那些被配置为会向客户端请求返回陈旧响应的缓存也不例外.

如果 no-cache 指令确实指定了一个或者多个 field-name, 那么缓存可以使用该响应来满足后续的请求, 但是要受到对缓存的任何其他限制的约束. 然而, 在没有与源服务器成功重新验证的情况下, 禁止在对后续请求的响应之中发送被指定的那些 field-name. 这允许源服务器阻止响应之中的某些头字段被重用, 同时仍然允许响应的其余部分被缓存.

注意: 大多数 HTTP/1.0 缓存不会识别也不会遵守这个指令.

14.9.2 缓存可以存储什么 (What May be Stored by Caches)​

no-store

no-store 指令的目的是防止敏感信息被无意地发布或者保留 (例如, 被保存在备份磁带之上). no-store 指令适用于整个消息, 它既可以在响应之中发送, 也可以在请求之中发送. 如果它是在请求之中发送的, 那么缓存禁止存储这个请求或者对它的任何响应的任何部分. 如果它是在响应之中发送的, 那么缓存禁止存储这个响应或者引发它的那个请求的任何部分. 这个指令既适用于非共享缓存, 也适用于共享缓存. 这里的 "禁止存储" 意味着: 缓存禁止有意地把信息存储到非易失性存储之中, 并且必须在把信息转发出去之后, 尽快地尽最大努力把信息从易失性存储之中移除.

即使这个指令是与响应相关联的, 用户也可能在缓存系统之外显式地存储这样一个响应 (例如, 通过一个 "另存为" 对话框). 历史缓冲区 (history buffers) 可以在它们的正常操作过程之中存储这类响应.

这个指令的目的是满足某些用户和服务作者所声明的要求, 他们担心通过未预期的、对缓存数据结构的访问而意外地泄露信息. 虽然使用这个指令在某些情况之下可能会改善隐私, 但是我们要提醒: 它无论如何都不是确保隐私的可靠或者充分的机制. 特别地, 恶意的或者被攻陷的缓存可能不识别也不遵守这个指令, 而且, 通信网络也可能会容易被窃听.

14.9.3 基本过期机制的修改 (Modifications of the Basic Expiration Mechanism)​

实体的过期时间可以由源服务器使用 Expires 头 (见第 14.21 节) 来指定. 作为另一种选择, 它也可以使用响应之中的 max-age 指令来指定. 当一个被缓存的响应之中存在 max-age 这个 cache-control 指令时, 如果在针对该资源发起新请求的那一刻, 该响应的当前 age 大于所给出的 age 值 (以秒计), 那么该响应就是陈旧的 (stale). 响应之上的 max-age 指令意味着该响应是可缓存的 (即 "public"), 除非同时还存在某个其他更具限制性的缓存指令.

如果一个响应既包含 Expires 头又包含 max-age 指令, 那么 max-age 指令就会覆盖 Expires 头, 即使 Expires 头更具限制性也是这样. 这条规则允许源服务器针对一个给定的响应, 向 HTTP/1.1 (或者更高版本) 的缓存提供比给 HTTP/1.0 缓存更长的过期时间. 如果某些 HTTP/1.0 缓存会不正确地计算 age 或者过期时间 (也许是由于时钟不同步), 那么这可能会很有用.

许多 HTTP/1.0 缓存实现会把小于或者等于响应 Date 值的 Expires 值, 当作是与 Cache-Control 响应指令 "no-cache" 等价的东西来对待. 如果一个 HTTP/1.1 缓存收到了这样的响应, 并且该响应没有包含 Cache-Control 头字段, 那么为了保持与 HTTP/1.0 服务器的兼容性, 它应当认为该响应是不可缓存的.

注意: 源服务器可能希望在一个包含着不理解较新的 HTTP 缓存控制特性 (例如 "private" 指令) 的旧缓存的网络之上, 使用这样一个特性. 源服务器将需要把新特性与一个值小于或者等于 Date 值的 Expires 字段结合在一起使用. 这样可以防止旧的缓存不适当地缓存该响应.

s-maxage

如果一个响应包含 s-maxage 指令, 那么对于共享缓存来说 (私有缓存不在此列), 这个指令所指定的最大 age 会覆盖 max-age 指令或者 Expires 头所指定的最大 age. s-maxage 指令还蕴含着 proxy-revalidate 指令 (见第 14.9.4 节) 的语义, 也就是说, 共享缓存在该条目变陈旧之后, 禁止在没有先与源服务器重新验证它的情况下, 用它来响应后续的请求. 私有缓存总是忽略 s-maxage 指令.

请注意, 大多数不符合本规范的旧缓存不实现任何 cache-control 指令. 希望使用某个 cache-control 指令来限制 (但不是阻止) 符合 HTTP/1.1 的缓存进行缓存的源服务器, 可以利用 "max-age 指令会覆盖 Expires 头" 这一要求, 以及 "HTTP/1.1 之前的缓存不观察 max-age 指令" 这一事实.

其他的指令允许用户代理修改基本的过期机制. 这些指令可以在请求之中指定:

max-age

表示客户端愿意接受 age 不大于指定时间 (以秒计) 的响应. 除非同时还包含 max-stale 指令, 否则客户端不愿意接受陈旧的响应.

min-fresh

表示客户端愿意接受这样的响应: 其 freshness lifetime 不小于它的当前 age 加上指定的时间 (以秒计). 也就是说, 客户端想要一个至少在指定秒数之内仍然是新鲜的响应.

max-stale

表示客户端愿意接受已经超过了它的过期时间的响应. 如果 max-stale 被赋予了一个值, 那么客户端愿意接受超过其过期时间不多于指定秒数的响应. 如果没有给 max-stale 赋值, 那么客户端愿意接受任何 age 的陈旧响应.

如果一个缓存返回了陈旧的响应, 无论是由于请求之中的 max-stale 指令, 还是由于缓存被配置为覆盖响应的过期时间, 该缓存都必须在这个陈旧的响应之上附加一个 Warning 头, 使用 Warning 110 (Response is stale).

缓存可以被配置为不经验证就返回陈旧的响应, 但是前提是这样做的结果不与任何关于缓存验证的 "MUST" 级别的要求 (例如 "must-revalidate" cache-control 指令) 相冲突.

如果新的请求和缓存条目都包含 "max-age" 指令, 那么就使用两者之中较小的那个值, 来确定这一次请求之下缓存条目的新鲜度.

14.9.4 缓存重新验证和重新加载控制 (Cache Revalidation and Reload Controls)​

有时候, 用户代理可能会想要或者需要坚持让缓存与源服务器 (而不仅仅是与通往源服务器的路径之上的下一个缓存) 重新验证它的缓存条目 (cache entry), 或者从源服务器重新加载它的缓存条目. 如果缓存或者源服务器高估了被缓存的响应的过期时间, 那么端到端的重新验证可能是必要的. 如果缓存条目由于某种原因而损坏了, 那么端到端的重新加载可能是必要的.

端到端重新验证既可以在客户端没有它自己的本地缓存副本的情况下请求, 这时我们把它称为 "未指定的端到端重新验证" (unspecified end-to-end revalidation); 也可以在客户端确实拥有本地缓存副本的情况下请求, 这时我们把它称为 "特定的端到端重新验证" (specific end-to-end revalidation).

客户端可以使用 Cache-Control 请求指令来指定下面这三种动作:

端到端重新加载 (End-to-end reload)

请求包含 "no-cache" cache-control 指令, 或者为了与 HTTP/1.0 客户端兼容而包含 "Pragma: no-cache". 在请求之中, no-cache 指令禁止附带字段名. 服务器在响应这样的请求时禁止使用缓存副本.

特定的端到端重新验证 (Specific end-to-end revalidation)

请求包含 "max-age=0" cache-control 指令, 它迫使通往源服务器的路径之上的每一级缓存与下一级缓存或者服务器重新验证它自己的条目 (如果有的话). 初始请求包含一个带有客户端当前验证器的缓存验证条件.

未指定的端到端重新验证 (Unspecified end-to-end revalidation)

请求包含 "max-age=0" cache-control 指令, 它迫使通往源服务器的路径之上的每一级缓存与下一级缓存或者服务器重新验证它自己的条目 (如果有的话). 初始请求不包含缓存验证条件; 路径之上第一个持有该资源缓存条目的缓存 (如果有的话) 会加入一个带有它当前的验证器的缓存验证条件.

max-age

当一个中间缓存因为 max-age=0 指令而被迫重新验证它自己的缓存条目, 并且客户端已经在请求之中提供了它自己的验证器 (validator) 时, 所提供的验证器可能与当前随缓存条目一起存储的验证器不同. 在这种情况下, 缓存在发起它自己的请求时可以使用两者之中的任何一个验证器, 而不会影响语义透明性 (semantic transparency).

然而, 验证器的选择可能会影响性能. 最好的做法是让中间缓存在发起它的请求时使用它自己的验证器. 如果服务器以 304 (Not Modified) 答复, 那么缓存就可以用 200 (OK) 响应把它那个现在已经被验证的副本返回给客户端. 而如果服务器以一个新实体和新的缓存验证器来答复, 那么中间缓存可以使用强比较函数, 把返回的验证器与客户端请求之中提供的验证器进行比较. 如果客户端的验证器与源服务器的验证器相等, 那么中间缓存就直接返回 304 (Not Modified). 否则, 它以 200 (OK) 响应返回那个新实体.

如果一个请求包含了 no-cache 指令, 那么它不应包含 min-fresh, max-stale 或者 max-age.

only-if-cached

在某些情况下, 例如网络连接极其糟糕的时候, 客户端可能希望缓存只返回它当前已经存储的那些响应, 而不要为了重新加载或者重新验证而去访问源服务器. 为了做到这一点, 客户端可以在请求之中包含 only-if-cached 指令. 如果收到了这个指令, 那么缓存应当或者使用与该请求的其他约束相一致的缓存条目来响应, 或者以 504 (Gateway Timeout) 状态来响应. 然而, 如果一组缓存作为一个内部连接良好的统一系统来运行, 那么这样的请求可以在该缓存组之内转发.

must-revalidate

由于缓存可以被配置为忽略服务器所指定的过期时间, 也由于客户端请求可以包含 max-stale 指令 (它有着类似的效果), 所以协议还包含了一种机制, 允许源服务器要求在后续的任何一次使用时都对缓存条目进行重新验证. 当缓存收到的响应之中存在 must-revalidate 指令时, 该缓存禁止在这个条目变陈旧之后, 在没有先与源服务器重新验证它的情况下, 用它来响应后续的请求. (也就是说, 如果仅仅根据源服务器的 Expires 或者 max-age 值来判断, 被缓存的响应就已经是陈旧的了, 那么缓存每一次都必须进行端到端的重新验证.)

must-revalidate 指令对于支持某些协议特性的可靠运行来说是必要的. 在任何情况下, HTTP/1.1 缓存都必须遵守 must-revalidate 指令; 特别地, 如果缓存由于任何原因而无法连接到源服务器, 那么它必须生成一个 504 (Gateway Timeout) 响应.

当对实体重新验证请求的失败可能导致不正确的操作时 (例如, 一笔财务交易被悄无声息地没有执行), 服务器应当发送 must-revalidate 指令, 并且仅应当在这种情况下发送. 接收方禁止采取任何违反这个指令的自动化动作, 并且禁止在重新验证失败时自动提供未经重新验证的实体副本.

尽管并不推荐这样做, 但是在严重的连通性约束之下运行的用户代理可以违反这个指令; 不过如果这样做, 那么它们必须明确地警告用户: 已经提供了未经验证的响应. 这个警告必须在每一次未经验证的访问时给出, 并且应当要求用户给出明确的确认.

proxy-revalidate

proxy-revalidate 指令与 must-revalidate 指令有着相同的含义, 区别在于它不适用于非共享的用户代理缓存. 它可以用在对已认证请求的响应之上, 以允许用户的缓存存储这个响应并且在其后返回它而无需重新验证 (因为它已经被该用户认证过一次了), 同时仍然要求那些服务许多用户的代理每一次都进行重新验证 (以便确保每一个用户都经过了认证). 请注意, 这类经过认证的响应还需要 public cache-control 指令, 才能够允许它们被缓存.

14.9.5 No-Transform 指令 (No-Transform Directive)​

no-transform

中间缓存 (代理) 的实现者们发现, 转换某些实体主体的媒体类型是很有用的. 例如, 一个非透明的代理可能会在图像格式之间进行转换, 以便节省缓存空间, 或者减少慢速链路之上的流量.

然而, 当这些转换被应用到面向某些种类的应用的实体主体之上时, 会出现严重的运行问题. 例如, 用于医学成像、科学数据分析的应用, 以及那些使用端到端认证的应用, 全都依赖于接收到与原始 entity-body 逐位相同的实体主体.

因此, 如果一条消息包含了 no-transform 指令, 那么中间缓存或者代理禁止改变第 13.5.2 节之中列为受 no-transform 指令约束的那些头. 这意味着缓存或者代理禁止改变这些头所规定的 entity-body 的任何方面, 包括 entity-body 本身的值.

14.9.6 缓存控制扩展 (Cache Control Extensions)​

Cache-Control 头字段可以通过使用一个或者多个 cache-extension 令牌来扩展, 其中每个令牌都可以带有一个可选的赋值. 信息性扩展 (即那些不需要改变缓存行为的扩展) 可以在不改变其他指令的语义的情况下添加. 行为性扩展在设计上是作为现有缓存指令基础的修饰符来起作用的. 新指令和标准指令被同时提供, 这样一来, 那些不理解新指令的应用程序就会默认采用标准指令所规定的行为, 而那些理解新指令的应用程序则会把它识别为对与标准指令相关联的要求的修改. 通过这种方式, 就可以在不要求改动基础协议的情况下, 对 cache-control 指令进行扩展.

这一扩展机制依赖于 HTTP 缓存遵守为它原生的 HTTP-version 所定义的所有 cache-control 指令, 遵守某些扩展, 并且忽略它所不理解的所有指令.

例如, 考虑一个假想的、名为 community 的新响应指令, 它充当 private 指令的修饰符. 我们把这个新指令定义为: 除了任何非共享缓存之外, 任何仅由它的值之中所命名的社区的成员所共享的缓存, 也可以缓存该响应. 希望允许 UCI 社区把一个原本私有的响应用在他们的共享缓存之中的源服务器, 可以通过包含下面这一行来做到:

       Cache-Control: private, community="UCI"

一个看到这个头字段的缓存, 即使它不理解 community 这个 cache-extension, 也会正确地行动, 因为它还会看到并且理解 private 指令, 从而默认采用安全的行为.

无法识别的 cache-directive 必须被忽略; 这里假定任何可能不被 HTTP/1.1 缓存识别的 cache-directive, 都会与标准指令 (或者与响应的默认可缓存性) 结合在一起使用, 这样一来, 即使缓存不理解这些扩展, 缓存的行为也仍然会保持最低限度的正确.

14.10 Connection​

Connection 通用头字段允许发送方指定只适用于该特定连接的选项, 并且禁止由代理在后续连接中传递.

Connection 头具有如下语法:

       Connection = "Connection" ":" 1#(connection-token)
connection-token = token

HTTP/1.1 代理必须在转发消息之前解析 Connection 头字段, 并且对于该字段中的每个 connection-token, 从消息中移除与该 connection-token 同名的所有头字段. 连接选项是通过 Connection 头字段中 connection-token 的出现来示意的, 而不是通过任何对应的其他头字段来示意的, 因为在没有与该连接选项相关联的参数时, 那个附加的头字段可能根本不会被发送.

Connection 头中列出的消息头禁止包含端到端头 (end-to-end headers), 例如 Cache-Control.

HTTP/1.1 定义了 "close" 连接选项, 供发送方示意连接将在响应完成后关闭. 例如,

       Connection: close

出现在请求或响应头字段中, 都表示在当前请求/响应完成之后, 该连接不应被视为 "持久" (persistent) 连接 (见第 8.1 节).

不支持持久连接的 HTTP/1.1 应用程序必须在每条消息中都包含 "close" 连接选项.

接收到含有 Connection 头的 HTTP/1.0 (或更低版本) 消息的系统, 必须对于该字段中的每个 connection-token, 从消息中移除并忽略与该 connection-token 同名的所有头字段. 这样可以防止此类头字段被 HTTP/1.1 之前的代理错误地转发. 见第 19.6.2 节.

14.11 Content-Encoding​

Content-Encoding 实体头字段作为 media-type 的修饰符使用. 当它存在时, 其值指出已经对实体主体应用了哪些额外内容编码 (content-coding), 因而必须应用哪些解码机制才能获得 Content-Type 头字段所引用的媒体类型. Content-Encoding 主要用于允许文档在不丢失其底层媒体类型身份的情况下被压缩.

       Content-Encoding  = "Content-Encoding" ":" 1#content-coding

内容编码定义见第 3.5 节. 一个使用示例是:

       Content-Encoding: gzip

content-coding 是由 Request-URI 所标识实体的一个特征. 通常, 实体主体以这种编码存储, 并且只在渲染或类似用途之前才被解码. 不过, 如果新的编码为接收方所知的可接受编码, 非透明代理可以修改 content-coding, 除非消息中存在 "no-transform" cache-control 指令.

如果实体的 content-coding 不是 "identity", 则响应必须包含一个列出所用非 identity content-coding 的 Content-Encoding 实体头 (见第 14.11 节).

如果请求消息中实体的 content-coding 不为源服务器所接受, 服务器应当以 415 (Unsupported Media Type) 状态码响应.

如果对实体应用了多种编码, 则内容编码必须按其被应用的顺序列出. 关于编码参数的附加信息可以由本规范未定义的其他实体头字段提供.

14.12 Content-Language​

Content-Language 实体头字段描述封闭实体面向受众的自然语言. 注意, 这不一定等同于实体主体中使用的所有语言.

       Content-Language  = "Content-Language" ":" 1#language-tag

语言标签定义见第 3.10 节. Content-Language 的主要目的, 是允许用户根据自己的偏好语言来识别和区分实体. 因此, 如果主体内容只面向懂丹麦语的受众, 适当的字段就是:

       Content-Language: da

如果未指定 Content-Language, 则默认认为内容面向所有语言受众. 这可能意味着发送方不认为内容特定于任何自然语言, 也可能意味着发送方不知道内容面向何种语言.

对于面向多个受众的内容, 可以列出多种语言. 例如, 同时以毛利语 (Maori) 原文和英语版本呈现的《怀唐伊条约》(Treaty of Waitangi) 文本, 应当写作:

       Content-Language: mi, en

不过, 实体中存在多种语言并不意味着它面向多个语言受众. 一个例子是初学者的语言入门读物, 例如《拉丁语第一课》(A First Lesson in Latin), 它显然是面向懂英语的受众使用的. 在这种情况下, Content-Language 应当只包含 "en".

Content-Language 可以应用于任何媒体类型 -- 它并不限于文本文档.

14.13 Content-Length​

Content-Length 实体头字段以十进制 OCTET 数表示发送给接收方的 entity-body 的大小, 或者在 HEAD 方法的情况下, 表示假如请求是 GET 时本应发送的 entity-body 的大小.

       Content-Length    = "Content-Length" ":" 1*DIGIT

一个示例是:

       Content-Length: 3495

应用程序应当使用该字段来指示 message-body 的传输长度 (transfer-length), 除非第 4.4 节的规则禁止这样做.

任何大于或等于零的 Content-Length 都是有效值. 当未给出 Content-Length 时, 第 4.4 节描述了如何确定 message-body 的长度.

注意, 该字段的含义与 MIME 中的对应定义有显著差别; 在 MIME 中, 它是在 "message/external-body" content-type 内使用的一个可选字段. 在 HTTP 中, 只要消息的长度能够在被传输之前确定, 就应当发送该字段, 除非第 4.4 节的规则禁止这样做.

14.14 Content-Location​

Content-Location 实体头字段可以用于提供消息中封闭实体的资源位置, 当该实体可以从不同于所请求资源 URI 的位置访问时尤其如此. 对于与响应实体相对应的变体, 服务器应当提供 Content-Location; 特别是当一个资源关联有多个实体, 且这些实体实际上各自拥有可以被单独访问的独立位置时, 服务器应当为所返回的那个特定变体提供 Content-Location.

       Content-Location = "Content-Location" ":"
( absoluteURI | relativeURI )

Content-Location 的值还定义了该实体的基 URI (base URI).

Content-Location 的值并不是对原始请求 URI 的替代; 它只是对与这个特定实体相对应的资源在请求时刻所处位置的说明. 如果后续请求希望标识那个特定实体的来源, 可以将 Content-Location URI 指定为 request-URI.

缓存不能想当然地认为, 一个 Content-Location 与获取它所用的 URI 不同的实体, 可以用来响应对那个 Content-Location URI 的后续请求. 不过, 如第 13.6 节所述, Content-Location 可以用来区分从单个被请求资源获取的多个实体.

如果 Content-Location 是一个相对 URI, 则该相对 URI 相对于 Request-URI 解释.

Content-Location 头在 PUT 或 POST 请求中的含义是未定义的; 在这些情况下, 服务器可以随意忽略它.

14.15 Content-MD5​

Content-MD5 实体头字段如 RFC 1864 [23] 所定义, 是 entity-body 的 MD5 摘要, 目的在于为 entity-body 提供端到端的消息完整性检查 (MIC, message integrity check). (注意: MIC 适合于检测 entity-body 在传输过程中的意外修改, 但并不能抵御恶意攻击.)

        Content-MD5   = "Content-MD5" ":" md5-digest
md5-digest = `<base64 of 128 bit MD5 digest as per RFC 1864>`

Content-MD5 头字段可以由源服务器或客户端生成, 用作 entity-body 的完整性检查. 只有源服务器或客户端可以生成 Content-MD5 头字段; 代理和网关禁止生成它, 因为这会使它作为端到端完整性检查的价值失效. entity-body 的任何接收者, 包括网关和代理, 都可以检查该头字段中的摘要值是否与所收到的 entity-body 相符.

MD5 摘要基于 entity-body 的内容计算, 包括已应用于它的任何 content-coding, 但不包括已应用于 message-body 的任何 transfer-encoding. 如果消息是连同 transfer-encoding 一起被接收的, 那么在对照所收到的实体检查 Content-MD5 值之前, 必须先移除该编码.

这样做的结果是, 摘要所针对的正是 entity-body 的那些八位组, 且其排列顺序与在没有任何 transfer-encoding 被应用的情况下本应发送时完全一致.

HTTP 对 RFC 1864 作了扩展, 允许为 MIME 复合媒体类型 (例如 multipart/* 和 message/rfc822) 计算摘要, 但这并不改变前一段所定义的摘要计算方式.

这会带来若干后果. 复合类型的 entity-body 可以包含许多 body-part, 每个 body-part 都有自己的 MIME 头和 HTTP 头 (包括 Content-MD5, Content-Transfer-Encoding 和 Content-Encoding 头). 如果某个 body-part 带有 Content-Transfer-Encoding 或 Content-Encoding 头, 则假定该 body-part 的内容已经应用了该编码, 并且该 body-part 按原样 -- 即在应用之后 -- 被纳入 Content-MD5 摘要. body-part 中不允许出现 Transfer-Encoding 头字段.

在计算或检查摘要之前, 禁止把所有换行统一转换为 CRLF: 计算摘要时, 实际传输文本所使用的换行约定必须保持原样不变.

注意: 尽管 Content-MD5 在 HTTP 中的定义与 RFC 1864 中针对 MIME entity-body 的定义完全相同, 但将 Content-MD5 应用于 HTTP entity-body 与应用于 MIME entity-body 在若干方面有所不同. 其一, HTTP 与 MIME 不同, 它不使用 Content-Transfer-Encoding, 而是使用 Transfer-Encoding 和 Content-Encoding. 其二, HTTP 比 MIME 更频繁地使用二进制内容类型, 因此值得注意, 在这种情况下, 计算摘要所用的字节序是该类型所定义的传输字节序. 最后, HTTP 允许以若干种换行约定中的任意一种来传输文本类型, 而不仅仅是使用 CRLF 的规范形式.

14.16 Content-Range​

Content-Range 实体头随部分 entity-body 一起发送, 用于指明该部分主体应施加于完整 entity-body 的哪个位置. 范围单位定义见第 3.12 节.

       Content-Range = "Content-Range" ":" content-range-spec

content-range-spec = byte-content-range-spec
byte-content-range-spec = bytes-unit SP
byte-range-resp-spec "/"
( instance-length | "*" )

byte-range-resp-spec = (first-byte-pos "-" last-byte-pos)
| "*"
instance-length = 1*DIGIT

该头应当指出完整 entity-body 的总长度, 除非该长度未知或难以确定. 星号 "*" 字符表示在生成响应时 instance-length 未知.

与 byte-ranges-specifier 值 (见第 14.35.1 节) 不同, byte-range-resp-spec 只能指定一个范围, 并且必须为该范围的第一个字节和最后一个字节都给出绝对字节位置.

如果一个 byte-content-range-spec 所带的 byte-range-resp-spec 的 last-byte-pos 值小于其 first-byte-pos 值, 或者其 instance-length 值小于或等于其 last-byte-pos 值, 则该 byte-content-range-spec 是无效的. 无效 byte-content-range-spec 的接收者必须忽略它以及随之一起传输的任何内容.

发送 416 (Requested range not satisfiable) 状态码响应的服务器应当在其中包含一个 byte-range-resp-spec 为 "" 的 Content-Range 字段. 该 instance-length 指明所选资源的当前长度. 状态码为 206 (Partial Content) 的响应禁止包含 byte-range-resp-spec 为 "" 的 Content-Range 字段.

byte-content-range-spec 值的示例, 假定实体总共包含 1234 字节:

      . The first 500 bytes:
bytes 0-499/1234

. The second 500 bytes:
bytes 500-999/1234

. All except for the first 500 bytes:
bytes 500-1233/1234

. The last 500 bytes:
bytes 734-1233/1234

当 HTTP 消息包含单个范围的内容时 (例如, 对单个范围请求的响应, 或对一组彼此重叠而无空洞的范围的请求的响应), 该内容用一个 Content-Range 头传输, 并附带一个表示实际传输字节数的 Content-Length 头. 例如:

       HTTP/1.1 206 Partial content
Date: Wed, 15 Nov 1995 06:25:24 GMT
Last-Modified: Wed, 15 Nov 1995 04:58:08 GMT
Content-Range: bytes 21010-47021/47022
Content-Length: 26012
Content-Type: image/gif

当 HTTP 消息包含多个范围的内容时 (例如, 对多个互不重叠范围的请求的响应), 这些内容作为 multipart 消息传输. 用于此目的的 multipart 媒体类型是附录 19.2 定义的 "multipart/byteranges". 相关的兼容性问题见附录 19.6.3.

对单个范围请求的响应禁止使用 multipart/byteranges 媒体类型发送. 对多个范围请求且结果为单一范围的响应, 可以作为只含一个 part 的 multipart/byteranges 媒体类型发送. 无法解码 multipart/byteranges 消息的客户端禁止在单个请求中请求多个 byte-range.

当客户端在一个请求中请求多个 byte-range 时, 服务器应当按这些范围在请求中出现的顺序返回它们.

如果服务器因为某个 byte-range-spec 语法无效而忽略它, 服务器应当像那个无效的 Range 头字段不存在一样处理该请求. (通常, 这意味着返回一个包含完整实体的 200 响应.)

如果服务器收到一个带有不可满足的 Range 请求头字段的请求 (即其所有 byte-range-spec 值的 first-byte-pos 值都大于所选资源的当前长度), 而该请求又不包含 If-Range 请求头字段, 那么服务器应当返回 416 (Requested range not satisfiable) 响应码 (见第 10.4.17 节).

注意: 客户端不能依赖服务器对不可满足的 Range 请求头返回 416 (Requested range not satisfiable) 响应而不是 200 (OK) 响应, 因为并非所有服务器都实现了这个请求头.

14.17 Content-Type​

Content-Type 实体头字段指出发送给接收方的 entity-body 的媒体类型, 或者在 HEAD 方法的情况下, 指出假如请求是 GET 时本应发送的媒体类型.

       Content-Type   = "Content-Type" ":" media-type

媒体类型定义见第 3.7 节. 该字段的一个示例是:

       Content-Type: text/html; charset=ISO-8859-4

关于识别实体媒体类型方法的进一步讨论见第 7.2.1 节.

14.18 Date​

Date 通用头字段表示消息产生的日期和时间, 其语义与 RFC 822 中的 orig-date 相同. 字段值是一个 HTTP-date, 如第 3.3.1 节所述; 它必须以 RFC 1123 [8] 日期格式发送.

       Date  = "Date" ":" HTTP-date

一个示例是:

       Date: Tue, 15 Nov 1994 08:12:31 GMT

源服务器必须在所有响应中包含 Date 头字段, 但以下情况除外:

  1. 如果响应状态码为 100 (Continue) 或 101 (Switching Protocols), 响应可以由服务器自行决定是否包含 Date 头字段.

  2. 如果响应状态码表示服务器错误, 例如 500 (Internal Server Error) 或 503 (Service Unavailable), 并且生成有效的 Date 不方便或不可能.

  3. 如果服务器没有能够提供当前时间合理近似值的时钟, 其响应禁止包含 Date 头字段. 在这种情况下, 必须遵循第 14.18.1 节的规则.

接收到的没有 Date 头字段的消息, 如果将被该接收者缓存, 或者将经由要求 Date 的协议进行网关转发, 则接收者必须为其分配一个 Date. 没有时钟的 HTTP 实现禁止缓存响应, 除非在每次使用时都重新验证. HTTP 缓存, 尤其是共享缓存, 应当使用某种机制 (例如 NTP [28]) 将其时钟与可靠的外部标准同步.

客户端应当只在包含 entity-body 的消息中发送 Date 头字段, 例如 PUT 和 POST 请求, 即便如此它也是可选的. 没有时钟的客户端禁止在请求中发送 Date 头字段.

Date 头中发送的 HTTP-date 不应表示晚于消息生成的日期和时间. 它应当表示对消息生成日期和时间的最佳可用近似值, 除非实现没有能力生成合理精确的日期和时间. 理论上, 该日期应当表示恰好在实体生成之前的那个时刻. 实践中, 该日期可以在消息生成期间的任意时刻产生, 而不影响其语义价值.

14.18.1 无时钟源服务器操作 (Clockless Origin Server Operation)​

某些源服务器实现可能没有可用时钟. 没有时钟的源服务器禁止为响应分配 Expires 或 Last-Modified 值, 除非这些值由拥有可靠时钟的系统或用户与资源关联. 它可以分配一个在服务器配置时或之前已知位于过去的 Expires 值, 这允许在不为每个资源单独存储 Expires 值的情况下让响应预过期.

14.19 ETag​

ETag 响应头字段提供所请求变体的当前实体标签 (entity tag) 值. 与实体标签配合使用的头见第 14.24、14.26 和 14.44 节. 实体标签可以用于与来自同一资源的其他实体进行比较 (见第 13.3.3 节).

      ETag = "ETag" ":" entity-tag

示例:

      ETag: "xyzzy"
ETag: W/"xyzzy"
ETag: ""

14.20 Expect​

Expect 请求头字段用于指示客户端要求特定服务器行为.

      Expect       =  "Expect" ":" 1#expectation

expectation = "100-continue" | expectation-extension
expectation-extension = token [ "=" ( token | quoted-string )
*expect-params ]
expect-params = ";" token [ "=" ( token | quoted-string ) ]

服务器如果不理解或无法遵守请求 Expect 字段中的任何期望值, 必须用适当的错误状态响应. 如果任何期望无法满足, 服务器必须响应 417 (Expectation Failed) 状态; 如果请求存在其他问题, 则响应其他某个 4xx 状态.

该头字段使用可扩展语法定义, 以允许未来的扩展. 如果服务器收到一个请求, 其 Expect 字段包含它不支持的 expectation-extension, 它必须响应 417 (Expectation Failed) 状态.

期望值的比较: 对于未加引号的 token (包括 100-continue token) 不区分大小写; 对于 quoted-string 形式的 expectation-extension 则区分大小写.

Expect 机制是逐跳的 (hop-by-hop): 也就是说, HTTP/1.1 代理如果收到一个带有它自己无法满足的期望的请求, 必须返回 417 (Expectation Failed) 状态. 不过, Expect 请求头本身是端到端的; 如果请求被转发, 它也必须被转发.

许多较老的 HTTP/1.0 和 HTTP/1.1 应用程序不理解 Expect 头.

关于 100 (Continue) 状态的使用见第 8.2.3 节.

14.21 Expires​

Expires 实体头字段给出响应在其后被认为陈旧 (stale) 的日期/时间. 陈旧的缓存条目通常不得由缓存 (无论是代理缓存还是用户代理缓存) 返回, 除非先与源服务器 (或与拥有该实体新鲜副本的中间缓存) 完成验证. 关于过期模型的进一步讨论见第 13.2 节.

Expires 字段的存在并不意味着原始资源会在该时刻、该时刻之前或之后改变或停止存在.

格式是第 3.3.1 节中 HTTP-date 所定义的绝对日期和时间; 它必须采用 RFC 1123 日期格式:

      Expires = "Expires" ":" HTTP-date

使用示例:

      Expires: Thu, 01 Dec 1994 16:00:00 GMT

注意: 如果响应包含带有 max-age 指令的 Cache-Control 字段 (见第 14.9.3 节), 该指令将覆盖 Expires 字段.

HTTP/1.1 客户端和缓存必须把其他无效的日期格式, 特别是其值 "0", 视为过去的时间 (即 "已经过期").

要把响应标记为 "已经过期", 源服务器发送一个与 Date 头值相等的 Expires 日期. (过期计算的规则见第 13.2.4 节.)

要把响应标记为 "永不过期", 源服务器发送一个距响应发送时刻约一年之后的 Expires 日期. HTTP/1.1 服务器不应发送超过未来一年以上的 Expires 日期.

在一个默认不可缓存的响应上, 如果其 Expires 头字段的日期值是未来的某个时刻, 这表示该响应是可缓存的, 除非 Cache-Control 头字段 (第 14.9 节) 另有指示.

14.22 From​

From 请求头字段如果给出, 应当包含控制发出请求的用户代理的人类用户的 Internet 电子邮件地址. 该地址应当按 RFC 822 [9] 中由 RFC 1123 [8] 更新的 "mailbox" 定义, 可由机器使用:

       From   = "From" ":" mailbox

示例:

该头字段可以用于日志记录, 也可用作识别无效或不想要请求来源的一种手段. 它不应被用作一种不安全的访问保护形式. 对该字段的解释是: 请求正代表所给出的人执行, 该人对所执行的方法承担责任. 特别是, 机器人 (robot) 代理应当包含该头, 以便在接收端出现问题时能够联系到运行该机器人的负责人.

该字段中的 Internet 电子邮件地址可以与发出该请求的 Internet 主机不同. 例如, 当请求经过代理传递时, 应当使用原始发出者的地址.

客户端不应在未经用户批准的情况下发送 From 头字段, 因为这可能与用户的隐私利益或其站点的安全策略相冲突. 强烈建议允许用户在请求发出之前的任意时刻禁用、启用和修改该字段的值.

14.23 Host​

Host 请求头字段指定被请求资源的 Internet 主机和端口号, 该值取自用户或引用资源给出的原始 URI (通常是 HTTP URL, 如第 3.2.2 节所述). Host 字段值必须表示原始 URL 给出的源服务器或网关的命名权威 (naming authority). 这使得源服务器或网关能够区分内部有歧义的 URL, 例如在单个 IP 地址上为多个主机名提供服务的服务器的根 "/" URL.

       Host = "Host" ":" host [ ":" port ] ; Section 3.2.2

不带任何尾随端口信息的 "host" 表示所请求服务的默认端口 (例如 HTTP URL 的 "80"). 例如, 对源服务器上 http://www.w3.org/pub/WWW/ 的请求应当恰当地包含:

       GET /pub/WWW/ HTTP/1.1
Host: www.w3.org

客户端必须在所有 HTTP/1.1 请求消息中包含 Host 头字段. 如果被请求的 URI 不包含所请求服务的 Internet 主机名, 则 Host 头字段必须以空值给出. HTTP/1.1 代理必须确保它转发的任何请求消息都确实包含一个能够标识该代理所请求服务的适当 Host 头字段. 所有基于 Internet 的 HTTP/1.1 服务器必须对任何缺少 Host 头字段的 HTTP/1.1 请求消息响应 400 (Bad Request) 状态码.

与 Host 相关的其他要求见第 5.2 节和第 19.6.1.1 节.

14.24 If-Match​

If-Match 请求头字段与某个方法一起使用, 以使该方法成为条件方法. 已经从资源获取过一个或多个实体的客户端, 可以通过在 If-Match 头字段中包含这些实体各自关联的实体标签列表, 来验证其中某个实体是否仍是最新的. 实体标签定义见第 3.11 节. 这一特性的目的在于, 以最少的事务开销高效地更新缓存信息. 在更新类请求中, 它还用于防止对资源的错误版本进行无意的修改. 作为一个特例, 值 "*" 匹配该资源的任何当前实体.

       If-Match = "If-Match" ":" ( "*" | 1#entity-tag )

如果任何一个实体标签与该资源上类似 GET 请求 (不带 If-Match 头) 的响应本应返回的实体的实体标签相匹配, 或者给出了 "*" 且该资源存在任何当前实体, 那么服务器可以像 If-Match 头字段不存在一样执行所请求的方法.

服务器必须使用强比较函数 (见第 13.3.3 节) 来比较 If-Match 中的实体标签.

如果没有一个实体标签匹配, 或者给出了 "*" 但不存在任何当前实体, 服务器禁止执行所请求的方法, 并且必须返回 412 (Precondition Failed) 响应. 这种行为在客户端想要阻止某个更新方法 (例如 PUT) 修改一个自客户端上次获取之后已经发生变化的资源时最为有用.

如果请求在没有 If-Match 头字段的情况下会得到 2xx 或 412 之外的任何状态, 那么必须忽略 If-Match 头.

"If-Match: *" 的含义是: 如果由源服务器 (或由缓存, 可能借助 Vary 机制, 见第 14.44 节) 选出的表示 (representation) 存在, 该方法应当被执行; 如果该表示不存在, 则禁止执行.

打算更新资源的请求 (例如 PUT) 可以包含一个 If-Match 头字段, 以示意: 如果与 If-Match 值 (单个实体标签) 相对应的实体不再是该资源的一个表示, 则禁止应用该请求方法. 这允许用户表明, 如果资源在用户不知情的情况下已被更改, 他们不希望请求获得成功. 示例:

       If-Match: "xyzzy"
If-Match: "xyzzy", "r2d2xxxx", "c3piozzzz"
If-Match: *

同时带有 If-Match 头字段以及 If-None-Match 或 If-Modified-Since 头字段的请求结果, 本规范未定义.

14.25 If-Modified-Since​

If-Modified-Since 请求头字段与某个方法一起使用, 使该方法成为条件方法: 如果所请求变体自该字段指定时间以来未被修改, 服务器不会返回实体, 而是返回不含 message-body 的 304 (Not Modified) 响应.

       If-Modified-Since = "If-Modified-Since" ":" HTTP-date

示例:

       If-Modified-Since: Sat, 29 Oct 1994 19:43:31 GMT

带 If-Modified-Since 头且不带 Range 头的 GET 方法请求, 要求仅当所标识实体自 If-Modified-Since 头给定的日期以来已被修改时才传输该实体. 判定这一点的算法包括以下几种情况:

  • a) 如果请求通常会产生 200 (OK) 以外的状态, 或者传入的 If-Modified-Since 日期无效, 则响应与普通 GET 完全相同. 晚于服务器当前时间的日期是无效的.
  • b) 如果变体自 If-Modified-Since 日期以来已被修改, 则响应与普通 GET 完全相同.
  • c) 如果变体自有效的 If-Modified-Since 日期以来未被修改, 服务器应当返回 304 (Not Modified) 响应.

该功能用于以最小事务开销高效更新缓存信息.

注意: Range 请求头字段会修改 If-Modified-Since 的含义; 完整细节见第 14.35 节.

注意: If-Modified-Since 时间由服务器解释, 服务器的时钟可能未与客户端同步.

注意: 在处理 If-Modified-Since 头字段时, 某些服务器会使用精确日期比较函数而非小于比较函数来决定是否发送 304 (Not Modified) 响应. 为在发送 If-Modified-Since 头字段做缓存验证时获得最佳结果, 建议客户端尽可能使用先前 Last-Modified 头字段中收到的精确日期字符串.

注意: 如果客户端在 If-Modified-Since 头中使用任意日期, 而不是取自同一请求的 Last-Modified 头的日期, 客户端应当意识到该日期是按服务器对时间的理解来解释的. 客户端应当考虑时钟不同步的问题, 以及客户端与服务器因时间编码不同而产生的舍入问题. 这包括: 如果文档在第一次被请求的时间与后续请求的 If-Modified-Since 日期之间发生了变化, 可能出现竞态条件; 以及如果 If-Modified-Since 日期取自客户端时钟而未向服务器时钟校正, 可能出现时钟偏差相关的问题. 由于网络延迟, 客户端与服务器之间不同时间基准的校正充其量只是近似.

同时带有 If-Modified-Since 头字段以及 If-Match 或 If-Unmodified-Since 头字段的请求结果, 本规范未定义.

14.26 If-None-Match​

If-None-Match 请求头字段与某个方法一起使用, 使该方法成为条件方法. 已从资源获取一个或多个实体的客户端, 可以通过在 If-None-Match 头字段中包含这些实体关联的实体标签列表, 验证这些实体都不是当前实体. 特殊值 "*" 匹配资源的任意当前实体.

       If-None-Match = "If-None-Match" ":" ( "*" | 1#entity-tag )

如果任何实体标签匹配该资源上类似 GET 请求 (不带 If-None-Match 头) 的响应本应返回的实体的实体标签, 或者给出 "*" 且该资源存在任何当前实体, 则服务器禁止执行所请求的方法, 除非因为请求中的 If-Modified-Since 头字段与资源修改日期不匹配而必须执行. 此时, 如果请求方法是 GET 或 HEAD, 服务器应当以 304 (Not Modified) 响应, 并包含匹配实体之一的缓存相关头字段 (尤其是 ETag). 对所有其他请求方法, 服务器必须以 412 (Precondition Failed) 状态响应.

判定两个实体标签是否匹配的规则见第 13.3.3 节. 弱比较函数只能用于 GET 或 HEAD 请求.

如果没有实体标签匹配, 则服务器可以像不存在 If-None-Match 头字段一样执行所请求的方法, 但也必须忽略请求中的任何 If-Modified-Since 头字段. 也就是说, 如果没有实体标签匹配, 服务器禁止返回 304 (Not Modified) 响应.

如果请求在没有 If-None-Match 头字段时会导致 2xx 或 304 之外的状态, 则必须忽略 If-None-Match 头. (同一请求中同时出现 If-Modified-Since 和 If-None-Match 时服务器行为的讨论见第 13.3.4 节.)

"If-None-Match: *" 的含义是: 如果源服务器 (或缓存, 可能使用 Vary 机制, 见第 14.44 节) 选定的表示存在, 则禁止执行该方法; 如果该表示不存在, 则应当执行该方法. 该功能旨在防止 PUT 操作之间的竞态.

示例:

       If-None-Match: "xyzzy"
If-None-Match: W/"xyzzy"
If-None-Match: "xyzzy", "r2d2xxxx", "c3piozzzz"
If-None-Match: W/"xyzzy", W/"r2d2xxxx", W/"c3piozzzz"
If-None-Match: *

同时带有 If-None-Match 头字段以及 If-Match 或 If-Unmodified-Since 头字段的请求结果, 本规范未定义.

14.27 If-Range​

如果客户端在其缓存中有某个实体的部分副本, 并希望得到整个实体的最新副本, 它可以把 Range 请求头与条件 GET 一起使用. 但是如果条件失败, 客户端还需要第二个请求来获取完整当前 entity-body.

If-Range 头允许客户端短路第二个请求. 非正式地说, 它的含义是: 如果实体未改变, 发送我缺少的部分; 否则, 发送整个新实体.

        If-Range = "If-Range" ":" ( entity-tag | HTTP-date )

如果客户端没有某实体的实体标签, 但有 Last-Modified 日期, 它可以在 If-Range 头中使用该日期. (服务器最多检查两个字符即可区分有效的 HTTP-date 与任何形式的实体标签.) If-Range 头应当只与 Range 头一起使用; 如果请求不包含 Range 头, 或者服务器不支持子范围操作, 则必须忽略 If-Range 头.

如果 If-Range 头中给出的实体标签与该实体当前的实体标签匹配, 服务器应当用 206 (Partial Content) 响应提供该实体的指定子范围. 如果实体标签不匹配, 服务器应当用 200 (OK) 响应返回整个实体.

14.28 If-Unmodified-Since​

If-Unmodified-Since 请求头字段与某个方法一起使用, 使该方法成为条件方法. 如果所请求资源自该字段指定时间以来未被修改, 服务器应当像不存在 If-Unmodified-Since 头一样执行所请求操作.

如果所请求变体自指定时间以来已被修改, 服务器禁止执行所请求操作, 并且必须返回 412 (Precondition Failed).

      If-Unmodified-Since = "If-Unmodified-Since" ":" HTTP-date

示例:

       If-Unmodified-Since: Sat, 29 Oct 1994 19:43:31 GMT

如果请求在没有 If-Unmodified-Since 头时通常会导致 2xx 或 412 之外的状态, 则应当忽略 If-Unmodified-Since 头.

如果指定日期无效, 则忽略该头.

同时带有 If-Unmodified-Since 头字段以及 If-None-Match 或 If-Modified-Since 头字段的请求结果, 本规范未定义.

14.29 Last-Modified​

Last-Modified 实体头字段指出源服务器认为该变体最后被修改的日期和时间.

       Last-Modified  = "Last-Modified" ":" HTTP-date

使用示例:

       Last-Modified: Tue, 15 Nov 1994 12:45:26 GMT

该头字段的精确含义取决于源服务器实现和原始资源性质. 对文件而言, 它可能是文件系统最后修改时间; 对动态实体而言, 它可能是组成部分最后修改时间中的最新值; 对数据库网关而言, 它可能是记录的最后更新时间戳; 对虚拟对象而言, 它可能是内部状态最后变化的时间.

源服务器禁止发送晚于服务器消息产生时间的 Last-Modified 日期. 在资源的最后修改时间指向未来的某些时刻, 服务器必须用消息产生日期替换该日期.

源服务器应当在尽可能接近生成其响应 Date 值的时间取得实体的 Last-Modified 值. 这使接收方能够准确评估实体的修改时间, 尤其当实体在响应生成时刻附近发生变化时.

HTTP/1.1 服务器应当在可行时发送 Last-Modified.

14.30 Location​

Location 响应头字段用于把接收方重定向到 Request-URI 之外的位置以完成请求, 或用于标识新资源. 对 201 (Created) 响应, Location 是该请求创建的新资源位置. 对 3xx 响应, 该位置应当指出服务器首选的自动重定向 URI. 字段值由单个绝对 URI 组成.

       Location       = "Location" ":" absoluteURI

示例:

       Location: http://www.w3.org/pub/WWW/People.html

注意: Content-Location 头字段 (第 14.14 节) 与 Location 不同, 因为 Content-Location 标识的是请求中封闭实体的原始位置. 因此, 一个响应有可能同时包含 Location 和 Content-Location 头字段. 另见第 13.10 节中某些方法的缓存要求.

14.31 Max-Forwards​

Max-Forwards 请求头字段为 TRACE 和 OPTIONS 方法提供一种机制, 用于限制能把请求转发到下一个入站服务器的代理或网关数量. 当客户端试图追踪一条似乎在中间失败或循环的请求链时, 这很有用.

       Max-Forwards   = "Max-Forwards" ":" 1*DIGIT

Max-Forwards 值是十进制整数, 表示该请求消息还可以被转发的次数. 每个收到包含 Max-Forwards 头字段的 TRACE 或 OPTIONS 请求的代理或网关, 在转发请求前必须检查并更新其值. 如果收到的值为 0, 接收方禁止转发请求; 它必须作为最终接收方响应. 如果值大于 0, 转发消息必须包含递减 1 后的 Max-Forwards 字段.

对于本规范定义的所有其他方法以及未在方法定义中显式引用 Max-Forwards 的任何扩展方法, 可以忽略 Max-Forwards 头字段.

14.32 Pragma​

Pragma 通用头字段用于包含实现特定的指令, 这些指令可能适用于请求/响应链上的任何接收方. 所有 pragma 指令从协议角度看都指定可选行为; 但某些系统可以要求行为与这些指令一致.

       Pragma            = "Pragma" ":" 1#pragma-directive
pragma-directive = "no-cache" | extension-pragma
extension-pragma = token [ "=" ( token | quoted-string ) ]

当请求消息中存在 no-cache 指令时, 应用应当把请求转发给源服务器, 即使它拥有所请求内容的缓存副本. 该 pragma 指令与 no-cache cache-directive 具有相同语义, 并在此为与 HTTP/1.0 向后兼容而定义. 当向未知是否兼容 HTTP/1.1 的服务器发送 no-cache 请求时, 客户端应当同时包含两个头字段.

Pragma 指令必须由代理或网关应用透传, 无论该指令对它自身是否有意义, 因为这些指令可能适用于请求/响应链上的所有接收方. 无法为特定接收方指定 pragma; 但是, 与某接收方无关的任何 pragma 指令应当被该接收方忽略.

HTTP/1.1 缓存应当把 "Pragma: no-cache" 视为客户端发送了 "Cache-Control: no-cache". HTTP 中不会再定义新的 Pragma 指令.

注意: 由于 "Pragma: no-cache" 作为响应头字段的含义实际上并未规定, 它不能在响应中为 "Cache-Control: no-cache" 提供可靠的替代.

14.33 Proxy-Authenticate​

Proxy-Authenticate 响应头字段必须作为 407 (Proxy Authentication Required) 响应的一部分包含. 字段值由 challenge 组成, 指出适用于该 Request-URI 的代理的认证方案和参数.

       Proxy-Authenticate  = "Proxy-Authenticate" ":" 1#challenge

HTTP 访问认证过程见 "HTTP Authentication: Basic and Digest Access Authentication" [43]. 与 WWW-Authenticate 不同, Proxy-Authenticate 头字段只适用于当前连接, 不应传递给下游客户端. 但是, 中间代理可能需要通过向下游客户端请求凭据来获得自己的凭据, 在某些情况下, 这看起来就像代理在转发 Proxy-Authenticate 头字段.

14.34 Proxy-Authorization​

Proxy-Authorization 请求头字段允许客户端向需要认证的代理标识自身或其用户. Proxy-Authorization 字段值由 credentials 组成, 包含用户代理针对代理和/或所请求资源领域的认证信息.

       Proxy-Authorization     = "Proxy-Authorization" ":" credentials

与 Authorization 不同, Proxy-Authorization 头字段只适用于使用 Proxy-Authenticate 字段要求认证的下一个出站代理. 当链中使用多个代理时, Proxy-Authorization 头字段由第一个期望接收凭据的出站代理消费. 如果这是代理协同认证某个请求的机制, 代理可以把客户端请求中的凭据中继给下一个代理.

14.35 Range​

14.35.1 字节范围 (Byte Ranges)​

由于所有 HTTP 实体在 HTTP 消息中都表示为字节序列, 字节范围概念对任何 HTTP 实体都有意义. 字节范围规范应用于 entity-body 中的字节序列, 该序列不一定与 message-body 相同. 字节范围操作可以指定单个字节范围, 也可以指定单个实体内的一组范围.

       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

byte-range-spec 中的 first-byte-pos 值给出范围中第一个字节的字节偏移. last-byte-pos 值给出范围中最后一个字节的字节偏移; 指定的字节位置是包含端点的. 字节偏移从 0 开始.

如果 last-byte-pos 存在, 它必须大于或等于 first-byte-pos, 否则语法无效. 接收方收到包含一个或多个语法无效 byte-range-spec 值的 byte-range-set 时, 必须忽略包含该 byte-range-set 的头字段. 如果 last-byte-pos 不存在或超过当前 entity-body 长度, 则视为当前 entity-body 长度减一.

通过选择 last-byte-pos, 客户端可以在不知道实体大小的情况下限制检索的字节数.

       suffix-byte-range-spec = "-" suffix-length
suffix-length = 1*DIGIT

suffix-byte-range-spec 用于指定 entity-body 的后缀, 长度由 suffix-length 给出. 如果实体短于指定 suffix-length, 则使用整个 entity-body.

如果语法有效的 byte-range-set 至少包含一个 first-byte-pos 小于当前 entity-body 长度的 byte-range-spec, 或至少包含一个非零 suffix-length 的 suffix-byte-range-spec, 则该 byte-range-set 可满足. 否则不可满足. 不可满足时服务器应当返回 416; 可满足时服务器应当返回 206, 其中包含 entity-body 的可满足范围.

byte-ranges-specifier 值的示例 (假定 entity-body 长度为 10000):

  • 前 500 个字节 (字节偏移 0-499, 含端点): bytes=0-499
  • 第二个 500 字节 (字节偏移 500-999, 含端点): bytes=500-999
  • 最后 500 个字节 (字节偏移 9500-9999, 含端点): bytes=-500
  • 或者: bytes=9500-
  • 仅第一个和最后一个字节 (字节 0 和 9999): bytes=0-0,-1
  • 第二个 500 字节的多种合法但非规范的写法 (字节偏移 500-999, 含端点):
       bytes=500-600,601-999
bytes=500-700,601-999

14.35.2 范围获取请求 (Range Retrieval Requests)​

使用条件或无条件 GET 方法的 HTTP 获取请求, 可以使用 Range 请求头请求实体的一个或多个子范围, 而不是整个实体. Range 应用于作为请求结果返回的实体:

      Range = "Range" ":" ranges-specifier

服务器可以忽略 Range 头. 但是 HTTP/1.1 源服务器和中间缓存应在可能时支持字节范围, 因为 Range 支持从部分失败传输中高效恢复, 也支持高效获取大型实体的一部分.

如果服务器支持 Range 头, 且指定的一个或多个范围适用于该实体:

  • 无条件 GET 中 Range 头的存在, 会在 GET 本来成功的情况下修改返回内容. 换言之, 响应携带的状态码是 206 (Partial Content) 而不是 200 (OK).
  • 条件 GET (使用 If-Modified-Since 和 If-None-Match 之一或两者, 或 If-Unmodified-Since 和 If-Match 之一或两者的请求) 中 Range 头的存在, 会在 GET 本来成功且条件为真的情况下修改返回内容. 它不影响条件为假时返回的 304 (Not Modified) 响应.

某些情况下, 在 Range 头之外再使用 If-Range 头 (见第 14.27 节) 可能更合适.

如果支持范围的代理收到 Range 请求, 把请求转发给入站服务器, 并在应答中收到完整实体, 它应当只向其客户端返回所请求的范围. 如果与其缓存分配策略一致, 它应当把收到的完整响应存储到自己的缓存中.

14.36 Referer​

Referer[sic] 请求头字段允许客户端为了服务器的利益, 指定获得 Request-URI 的来源资源地址 (URI), 即 "referrer", 尽管该头字段拼写错误. Referer 请求头允许服务器生成指向资源的反向链接列表, 用于关注度分析、日志、优化缓存等. 它也允许追踪过时或拼写错误的链接以便维护. 如果 Request-URI 来自没有自身 URI 的来源, 例如用户键盘输入, 则禁止发送 Referer 字段.

       Referer        = "Referer" ":" ( absoluteURI | relativeURI )

示例:

       Referer: http://www.w3.org/hypertext/DataSources/Overview.html

如果字段值是相对 URI, 应当相对于 Request-URI 解释. URI 禁止包含 fragment. 安全考虑见第 15.1.3 节.

14.37 Retry-After​

Retry-After 响应头字段可与 503 (Service Unavailable) 响应一起使用, 指出服务预计对请求客户端不可用多长时间. 该字段也可以与任何 3xx 响应一起使用, 指出要求用户代理在发出重定向请求前等待的最短时间. 字段值可以是 HTTP-date, 也可以是响应时间之后的十进制秒数整数.

       Retry-After  = "Retry-After" ":" ( HTTP-date | delta-seconds )

示例:

       Retry-After: Fri, 31 Dec 1999 23:59:59 GMT
Retry-After: 120

后一示例中的延迟为 2 分钟.

14.38 Server​

Server 响应头字段包含源服务器处理请求所用软件的信息. 该字段可以包含多个 product 令牌和注释, 用于标识服务器及任何重要子产品. product 令牌按其对标识应用的重要性排序.

       Server         = "Server" ":" 1*( product | comment )

示例:

       Server: CERN/3.0 libwww/2.17

如果响应通过代理转发, 代理应用禁止修改 Server 响应头. 暴露具体服务器软件版本可能让服务器更容易遭受针对已知安全漏洞的攻击, 因此鼓励服务器实现把该字段设为可配置选项.

14.39 TE​

TE 请求头字段指出客户端愿意在响应中接受哪些扩展传输编码 (extension transfer-codings), 以及它是否愿意接受 chunked 传输编码中的 trailer 字段. 其值可以由关键字 "trailers" 和/或一个以逗号分隔的扩展传输编码名称列表组成, 并可带有可选的接受参数 (accept parameters, 见第 3.6 节的描述).

       TE        = "TE" ":" #( t-codings )
t-codings = "trailers" | ( transfer-extension [ accept-params ] )

关键字 "trailers" 的出现表示客户端愿意接受 chunked 传输编码中的 trailer 字段, 如第 3.6.1 节所定义. 该关键字保留用于传输编码值之中, 尽管它本身并不表示一种传输编码.

使用示例:

       TE: deflate
TE:
TE: trailers, deflate;q=0.5

TE 头字段只适用于直接连接. 因此, 只要 HTTP/1.1 消息中出现了 TE, 就必须在 Connection 头字段 (第 14.10 节) 之中提供该关键字.

服务器依据 TE 字段测试某个传输编码是否可接受, 使用以下规则:

  1. "chunked" 传输编码总是可接受的. 如果列出了关键字 "trailers", 则客户端表示: 它愿意代表自己以及任何下游客户端接受 chunked 响应中的 trailer 字段. 这意味着, 如果给出了该关键字, 客户端是在声明: 要么所有下游客户端都愿意接受被转发响应中的 trailer 字段, 要么它将尝试代表下游接收方缓冲该响应.

    注意: HTTP/1.1 并未定义任何限制 chunked 响应大小的手段, 使客户端能够确保缓冲整个响应.

  2. 如果被测试的传输编码是 TE 字段中列出的传输编码之一, 则它是可接受的, 除非它伴随着一个为 0 的 qvalue. (如第 3.9 节所定义, qvalue 为 0 意味着 "不可接受".)

  3. 如果多个传输编码都是可接受的, 那么优先选择具有最高非零 qvalue 的可接受传输编码. "chunked" 传输编码的 qvalue 总是为 1.

如果 TE 字段值为空, 或者不存在 TE 字段, 则唯一可接受的传输编码是 "chunked". 不带传输编码的消息总是可接受的.

14.40 Trailer​

Trailer 通用字段值表示给定的一组头字段存在于以 chunked 传输编码编码的消息的 trailer 之中.

       Trailer  = "Trailer" ":" 1#field-name

使用 chunked 传输编码且带有非空 trailer 的 HTTP/1.1 消息应当包含一个 Trailer 头字段. 这样做使接收方能够预先知道在 trailer 中应当预期哪些头字段.

如果不存在 Trailer 头字段, 则 trailer 不应包含任何头字段. 关于在 "chunked" 传输编码中使用 trailer 字段的限制, 见第 3.6.1 节.

Trailer 头字段中列出的消息头字段禁止包含以下头字段:

  • Transfer-Encoding

  • Content-Length

  • Trailer

14.41 Transfer-Encoding​

Transfer-Encoding 通用头字段指出为了在发送方和接收方之间安全地传输消息主体, 已经对 message-body 应用了何种 (如果有的话) 类型的变换. 这与 content-coding 的不同之处在于: transfer-coding 是消息的属性, 而不是实体的属性.

     Transfer-Encoding       = "Transfer-Encoding" ":" 1#transfer-coding

传输编码定义见第 3.6 节. 一个示例是:

     Transfer-Encoding: chunked

如果对实体应用了多种编码, 则传输编码必须按其被应用的顺序列出. 关于编码参数的附加信息可以由本规范未定义的其他实体头字段提供.

许多较老的 HTTP/1.0 应用程序不理解 Transfer-Encoding 头.

14.42 Upgrade​

Upgrade 通用头字段允许客户端指定它支持并且希望使用的其他通信协议, 如果服务器认为切换协议是恰当的话. 服务器必须在 101 (Switching Protocols) 响应之中使用 Upgrade 头字段, 以指示正在切换到哪些协议.

       Upgrade        = "Upgrade" ":" 1#product

例如:

       Upgrade: HTTP/2.0, SHTTP/1.3, IRC/6.9, RTA/x11

Upgrade 头字段旨在提供一种从 HTTP/1.1 过渡到其他某种不兼容协议的简单机制. 它的做法是: 允许客户端表明自己希望使用另一种协议 (例如主版本号更高的 HTTP 后续版本), 即便当前请求是使用 HTTP/1.1 发出的. 这通过以下方式缓解了不兼容协议之间困难的过渡: 允许客户端以受到更普遍支持的协议发起请求, 同时向服务器表明: 如果有 "更好" 的协议可用, 它愿意使用之 (其中 "更好" 由服务器判定, 可能依据所请求的方法和/或资源的性质).

Upgrade 头字段只适用于在现有传输层连接之上切换应用层协议. Upgrade 不能被用来坚持要求协议切换; 服务器对它的接受与使用是可选的. 协议切换之后应用层通信的能力与性质完全取决于所选的新协议, 尽管协议切换之后的第一个动作必须是对包含 Upgrade 头字段的初始 HTTP 请求的响应.

Upgrade 头字段只适用于直接连接. 因此, 只要 HTTP/1.1 消息中出现了 Upgrade, 就必须在 Connection 头字段 (第 14.10 节) 之中提供 upgrade 关键字.

Upgrade 头字段不能用于指示切换到另一个连接上的协议. 为此目的, 使用 301、302、303 或 305 重定向响应更为恰当.

本规范只定义协议名 "HTTP", 供超文本传输协议家族使用, 如第 3.1 节的 HTTP 版本规则以及本规范的后续更新所定义. 任何 token 都可以用作协议名; 然而, 只有当客户端和服务器都把该名字与同一个协议关联起来时, 它才有用处.

14.43 User-Agent​

User-Agent 请求头字段包含发起该请求的用户代理的信息. 它用于统计目的、协议违规的追踪, 以及对用户代理的自动识别, 以便量身定制响应来规避特定用户代理的局限. 用户代理应当在请求中包含该字段. 该字段可以包含多个 product 令牌 (见第 3.8 节) 和注释, 用于标识该用户代理以及构成其重要部分的任何子产品. 按照惯例, product 令牌按其对标识应用的重要性顺序列出.

       User-Agent     = "User-Agent" ":" 1*( product | comment )

示例:

       User-Agent: CERN-LineMode/2.15 libwww/2.17b3

14.44 Vary​

Vary 字段值指出这样一组请求头字段: 在响应处于新鲜状态期间, 它们完全决定缓存是否被允许使用该响应来答复后续的请求而无需重新验证. 对不可缓存或陈旧的响应, Vary 字段值向用户代理提示选择该表示时所依据的判据. Vary 字段值为 "*" 意味着: 缓存无法根据后续请求的请求头判断该响应是否就是恰当的表示. 关于缓存对 Vary 头字段的使用见第 13.6 节.

       Vary  = "Vary" ":" ( "*" | 1#field-name )

HTTP/1.1 服务器应当在任何经受服务器驱动协商 (server-driven negotiation) 的可缓存响应中包含一个 Vary 头字段. 这样做使缓存能够正确解释将来对该资源的请求, 并告知用户代理该资源之上存在协商. 对于经受服务器驱动协商的不可缓存响应, 服务器可以包含一个 Vary 头字段, 因为这可以向用户代理提供关于该响应在响应时刻于哪些维度上发生变化的有用信息.

由 field-name 列表构成的 Vary 字段值表明: 为响应所选出的表示, 是由一个在选择最恰当表示时只考虑被列出的那些请求头字段值的选择算法得出的. 缓存可以假定: 在该响应处于新鲜状态的时间段内, 对于被列出字段名具有相同取值的将来请求, 将会做出相同的选择.

所给出的 field-name 不限于本规范定义的标准请求头字段集合. 字段名不区分大小写.

Vary 字段值为 "" 表示: 有不限于请求头的未指明参数 (例如客户端的网络地址) 参与了响应表示的选择. "" 值禁止由代理服务器生成; 它只能由源服务器生成.

14.45 Via​

网关和代理必须使用 Via 通用头字段, 以指示请求中用户代理与服务器之间、响应中源服务器与客户端之间的中间协议和接收方. 它类似于 RFC 822 [9] 的 "Received" 字段, 旨在用于追踪消息转发、避免请求循环, 以及识别请求/响应链上所有发送方的协议能力.

      Via =  "Via" ":" 1#( received-protocol received-by [ comment ] )
received-protocol = [ protocol-name "/" ] protocol-version
protocol-name = token
protocol-version = token
received-by = ( host [ ":" port ] ) | pseudonym
pseudonym = token

received-protocol 表示请求/响应链每一段上的服务器或客户端所收到消息的协议版本. 当消息被转发时, received-protocol 版本会被附加到 Via 字段值之中, 使得关于上游应用协议能力的信息对所有接收方保持可见.

当且仅当协议名会是 "HTTP" 时, protocol-name 才可以省略. received-by 字段通常是随后转发该消息的接收方服务器或客户端的主机名和可选端口号. 然而, 如果真实主机名被视为敏感信息, 它可以替换为一个假名 (pseudonym). 如果未给出端口, 则可以假定它是 received-protocol 的默认端口.

多个 Via 字段值表示转发过该消息的每一个代理或网关. 每个接收方必须附加自己的信息, 使得最终结果按照转发应用的先后顺序排列.

注释可以用于 Via 头字段之中, 以标识接收方代理或网关的软件, 类似于 User-Agent 和 Server 头字段. 然而, Via 字段中的所有注释都是可选的, 任何接收方都可以在转发消息之前将其移除.

示例:

       Via: 1.0 fred, 1.1 nowhere.com (Apache/1.1)

作为网络防火墙门户的代理和网关默认不应转发防火墙区域内主机的名称和端口. 只有在显式启用时才应传播这些信息. 如未启用, 防火墙后任何主机的 received-by 主机应当替换为适当的 pseudonym.

对于有强隐私要求、需要隐藏内部结构的组织, 代理可以把 received-protocol 值相同的有序 Via 条目子序列合并为单个条目. 例如:

       Via: 1.0 ricky, 1.1 ethel, 1.1 fred, 1.0 lucy

Via: 1.0 ricky, 1.1 mertz, 1.0 lucy

应用不应合并多个条目, 除非它们都处于同一组织控制之下且主机已被替换为 pseudonym. 应用禁止合并 received-protocol 值不同的条目.

14.46 Warning​

Warning 通用头字段用于携带关于消息状态或转换的附加信息, 这些信息可能未在消息中反映出来. 这些信息通常用于警告缓存操作或对消息 entity-body 应用转换可能导致语义透明性不足.

Warning 头随响应发送:

       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
; the name or pseudonym of the server adding
; the Warning header, for use in debugging
warn-text = quoted-string
warn-date = `<">` HTTP-date `<">`

响应可以携带多个 Warning 头. warn-text 应当使用接收响应的人类用户最可能理解的自然语言和字符集. 默认语言为英语, 默认字符集为 ISO-8859-1. 如果使用 ISO-8859-1 之外的字符集, 必须用 RFC 2047 [14] 描述的方法在 warn-text 中编码.

Warning 头通常可应用于任何消息, 但某些 warn-code 专用于缓存, 只能应用于响应消息. 新 Warning 头应当添加在已有 Warning 头之后. 缓存禁止删除随消息收到的任何 Warning 头. 但是, 如果缓存成功验证缓存条目, 除特定 Warning code 另有规定外, 它应当移除先前附加到该条目的 Warning 头. 然后它必须添加验证响应中收到的任何 Warning 头. 换言之, Warning 头就是那些应当附加于最近的相关响应的头.

当响应附加多个 Warning 头时, 用户代理应当尽可能多地把它们告知用户, 并按照它们在响应中出现的顺序. 如果无法把所有警告都告知用户, 用户代理应当遵循以下启发式规则:

  • 在响应中较早出现的警告, 优先于较晚出现的警告.

  • 用户首选字符集的警告, 优先于其他字符集但 warn-code 与 warn-agent 相同的警告.

生成多个 Warning 头的系统, 应当把这种用户代理行为考虑在内来为它们排序.

缓存对 Warning 的行为要求在第 13.1.2 节中陈述.

当前定义的 warn-code 如下:

   110 Response is stale

每当返回的响应已陈旧时必须包含.

   111 Revalidation failed

如果缓存因为无法联系服务器而重新验证失败, 因此返回陈旧响应, 则必须包含.

   112 Disconnected operation

如果缓存有意在一段时间内与网络其他部分断开连接, 则应当包含.

   113 Heuristic expiration

如果缓存用启发式方法选择了超过 24 小时的新鲜寿命, 且响应 age 超过 24 小时, 则必须包含.

   199 Miscellaneous warning

警告文本可以包含任意要呈现给人类用户或记录的信息. 收到此警告的系统除向用户呈现警告外, 禁止采取任何自动动作.

   214 Transformation applied

如果中间缓存或代理应用了任何改变响应 content-coding、media-type 或 entity-body 的转换, 必须添加该警告, 除非响应中已出现此 Warning code.

   299 Miscellaneous persistent warning

警告文本可以包含任意要呈现给人类用户或记录的信息. 收到此警告的系统禁止采取任何自动动作.

如果实现发送带有一个或多个 Warning 头且版本为 HTTP/1.0 或更低的消息, 发送方必须在每个 warning-value 中包含与响应 Date 匹配的 warn-date. 如果实现收到包含 warn-date 的 warning-value, 且该 warn-date 与响应 Date 值不同, 则在存储、转发或使用消息前必须删除该 warning-value. (这可以防止对 Warning 头字段进行天真缓存所带来的不良后果.) 如果所有 warning-value 都因此被删除, 那么 Warning 头也必须删除.

14.47 WWW-Authenticate​

WWW-Authenticate 响应头字段必须包含在 401 (Unauthorized) 响应消息中. 字段值由至少一个 challenge 组成, 指出适用于 Request-URI 的认证方案和参数.

       WWW-Authenticate  = "WWW-Authenticate" ":" 1#challenge

HTTP 访问认证过程见 "HTTP Authentication: Basic and Digest Access Authentication" [43]. 建议用户代理在解析 WWW-Authenticate 字段值时特别小心, 因为它可能包含多个 challenge; 或者如果提供了多个 WWW-Authenticate 头字段, challenge 本身的内容也可能包含逗号分隔的认证参数列表.