跳到主要内容

7. 响应头部字段

响应头部字段允许服务器传递除 status-line 中内容之外的响应附加信息. 这些头部字段提供有关服务器、对目标资源的进一步访问, 或相关资源的信息.

虽然每个响应头部字段都有定义的含义, 但一般而言, 精确语义可能会由请求方法和/或响应状态码的语义进一步细化.

7.1. 控制数据

响应头部字段可以提供控制数据, 用于补充状态码、指引缓存, 或指示客户端下一步去哪里.

7.1.1. 发起日期

7.1.1.1. Date

"Date" 头部字段表示消息发起的日期和时间, 其语义与 [RFC5322] Section 3.6.1 中定义的 Origination Date Field (orig-date) 相同. 字段值是 HTTP-date, 如 [RFC7231] Section 7.1.1.1 所定义.

Date = HTTP-date

示例为:

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

生成 Date 头部字段时, 发送者 SHOULD 将其字段值生成为消息生成日期和时间的最佳可用近似值. 理论上, 日期应表示负载生成前的那一刻. 实践中, 日期可以在消息发起期间的任何时间生成.

如果源服务器没有能够提供协调世界时当前时刻合理近似值的时钟, 则源服务器 MUST NOT 发送 Date 头部字段. 如果响应属于 1xx (Informational) 或 5xx (Server Error) 状态码类别, 源服务器 MAY 发送 Date 头部字段. 在所有其他情况下, 源服务器 MUST 发送 Date 头部字段.

具有时钟的接收者如果收到不带 Date 头部字段的响应消息, MUST 记录收到该消息的时间, 并在该消息被缓存或向下游转发时向消息头部节追加相应的 Date 头部字段.

用户代理 MAY 在请求中发送 Date 头部字段, 但通常不会这样做, 除非认为它能向服务器传达有用信息. 例如, HTTP 的自定义应用如果期望服务器根据用户代理和服务器时钟之间的差异来调整其对用户请求的解释, 可能会传达 Date.

7.1.1.2. HTTP-date

HTTP 应用历史上允许用三种不同格式表示日期/时间戳:

Sun, 06 Nov 1994 08:49:37 GMT  ; IMF-fixdate
Sunday, 06-Nov-94 08:49:37 GMT ; obsolete RFC 850 format
Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format

第一种格式作为 Internet 标准是首选格式, 表示 [RFC5322] (Section 3.3) 所定义格式的固定长度子集. 第二种格式被普遍使用, 但基于已废弃的 RFC 850 [RFC0850] 日期格式, 且缺少四位年份. 解析日期值的 HTTP/1.1 客户端和服务器 MUST 接受全部三种格式 (为兼容 HTTP/1.0), 但在头部字段中表示 HTTP-date 值时 MUST 只生成 IMF-fixdate 格式.

注意: rfc850-date 格式的时间戳值使用两位年份, 其接收者 MUST 将看起来超过未来 50 年的时间戳解释为过去最近一个末两位数字相同的年份.

HTTP-date 值把时间表示为协调世界时 (UTC) 的一个时刻. 前两种格式通过格林尼治标准时间的三字母缩写 "GMT" 指示 UTC, GMT 是 UTC 名称的前身; asctime 格式中的值假定为 UTC. 从本地时钟生成 HTTP-date 值的发送者应使用 NTP ([RFC5905]) 或某种类似协议将其时钟同步到 UTC.

首选格式:

HTTP-date    = IMF-fixdate / obs-date

IMF-fixdate = day-name "," SP date1 SP time-of-day SP GMT
; fixed length/zone/capitalization subset of the format
; see Section 3.3 of [RFC5322]

day-name = %x4D.6F.6E ; "Mon", case-sensitive
/ %x54.75.65 ; "Tue", case-sensitive
/ %x57.65.64 ; "Wed", case-sensitive
/ %x54.68.75 ; "Thu", case-sensitive
/ %x46.72.69 ; "Fri", case-sensitive
/ %x53.61.74 ; "Sat", case-sensitive
/ %x53.75.6E ; "Sun", case-sensitive

date1 = day SP month SP year
; e.g., 02 Jun 1982

day = 2DIGIT
month = %x4A.61.6E ; "Jan", case-sensitive
/ %x46.65.62 ; "Feb", case-sensitive
/ %x4D.61.72 ; "Mar", case-sensitive
/ %x41.70.72 ; "Apr", case-sensitive
/ %x4D.61.79 ; "May", case-sensitive
/ %x4A.75.6E ; "Jun", case-sensitive
/ %x4A.75.6C ; "Jul", case-sensitive
/ %x41.75.67 ; "Aug", case-sensitive
/ %x53.65.70 ; "Sep", case-sensitive
/ %x4F.63.74 ; "Oct", case-sensitive
/ %x4E.6F.76 ; "Nov", case-sensitive
/ %x44.65.63 ; "Dec", case-sensitive
year = 4DIGIT

GMT = %x47.4D.54 ; "GMT", case-sensitive

time-of-day = hour ":" minute ":" second
; 00:00:00 - 23:59:60 (leap second)

hour = 2DIGIT
minute = 2DIGIT
second = 2DIGIT

废弃格式:

obs-date     = rfc850-date / asctime-date

rfc850-date = day-name-l "," SP date2 SP time-of-day SP GMT
date2 = day "-" month "-" 2DIGIT
; e.g., 02-Jun-82

day-name-l = %x4D.6F.6E.64.61.79 ; "Monday", case-sensitive
/ %x54.75.65.73.64.61.79 ; "Tuesday", case-sensitive
/ %x57.65.64.6E.65.73.64.61.79 ; "Wednesday", case-sensitive
/ %x54.68.75.72.73.64.61.79 ; "Thursday", case-sensitive
/ %x46.72.69.64.61.79 ; "Friday", case-sensitive
/ %x53.61.74.75.72.64.61.79 ; "Saturday", case-sensitive
/ %x53.75.6E.64.61.79 ; "Sunday", case-sensitive

asctime-date = day-name SP date3 SP time-of-day SP year
date3 = month SP ( 2DIGIT / ( SP 1DIGIT ))
; e.g., Jun 2

HTTP-date 区分大小写. 发送者 MUST NOT 在 HTTP-date 中生成除语法中明确作为 SP 包含的空白之外的额外空白. day-name、day、month、year, 和 time-of-day 的语义与 Internet Message Format 中同名结构的定义相同 ([RFC5322] Section 3.3).

7.1.2. Location

"Location" 头部字段在某些响应中用于引用与响应相关的特定资源. 关系类型由请求方法和状态码语义的组合定义.

Location = URI-reference

字段值由单个 URI-reference 组成. 当其形式为相对引用 ([RFC3986] Section 4.2) 时, 最终值通过相对于有效请求 URI ([RFC7230] Section 5.5) 解析而计算.

对于 201 (Created) 响应, Location 值是对一个资源的 URI 引用, 该资源标识请求创建的主资源. 对于 3xx (Redirection) 响应, Location 值引用自动重定向请求时的首选目标资源.

如果 3xx (Redirection) 响应中提供的 Location 值没有 fragment 组件, 用户代理 MUST 像该值继承了用于生成请求目标的 URI 引用的 fragment 组件那样处理重定向 (即, 重定向继承原始引用的 fragment, 如果有).

例如, 为 URI 引用 "http://www.example.org/~tim" 生成的 GET 请求, 可能在最终到达 "http://www.example.com/~tim/" 之前经历多次重定向. 如果第一次重定向到 "http://www.example.org/people/~tim", 那么该重定向将指向 "http://www.example.org/people/~tim", 而不是 "http://www.example.org/people/~tim#fred".

在某些情况下, Location 值中的 fragment 标识符并不合适. 例如, 201 (Created) 响应中的 Location 头部字段应提供一个专属于所创建资源的 URI.

注意: 一些接收者试图从无效 URI 引用的 Location 字段中恢复. 本规范不强制或定义这种处理, 但为稳健性允许这样做. 值为 absolute-path 的 Location 字段是可接受的, 但会相对于有效请求 URI 解释.

注意: 响应的内容协商可能导致 Location 值不同于有效请求 URI. 如果响应可缓存, 缓存可以使用该 Location 值来为响应确定更合适的键 (见 [RFC7234] Section 4.1).

7.1.3. Retry-After

服务器发送 "Retry-After" 头部字段, 以指示用户代理在发出后续请求之前应等待多久. 与 503 (Service Unavailable) 响应一起发送时, Retry-After 指示服务预计对客户端不可用多长时间. 与 429 (Too Many Requests) 响应一起发送时, Retry-After 指示用户代理在发出后续请求之前应等待多久. 与任何 3xx (Redirection) 响应一起发送时, Retry-After 指示要求用户代理在发出重定向请求之前等待的最短时间.

该字段的值可以是 HTTP-date, 也可以是收到响应后延迟的秒数.

Retry-After = HTTP-date / delay-seconds

delay-seconds 值是一个非负十进制整数, 表示秒数.

delay-seconds = 1*DIGIT

以下是两个使用示例:

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

在后一个示例中, 延迟为 2 分钟.

7.1.4. Vary

响应中的 "Vary" 头部字段描述请求消息中除方法和请求目标之外, 哪些部分可能影响源服务器选择并表示此响应的过程. 其值要么是单个星号 ("*"), 要么是头部字段名称列表 (不区分大小写).

Vary = "*" / 1#field-name

Vary 字段值 "" 表示请求的任何方面都可能在选择响应表示时发挥作用, 可能包括消息语法之外的元素 (例如客户端网络地址). 接收者若不把请求转发给源服务器, 将无法确定此响应是否适合后续请求. 代理 MUST NOT 生成值为 "" 的 Vary 字段.

由逗号分隔名称列表组成的 Vary 字段值指示, 命名的请求头部字段 (称为 selecting request header fields) 可能在选择表示时发挥作用. 潜在的 selecting request header fields 不限于本规范定义的字段.

例如, 包含以下内容的响应:

Vary: accept-encoding, accept-language

指示源服务器在为此响应选择内容时, 可能使用了请求的 Accept-EncodingAccept-Language 字段 (或其缺失) 作为决定因素.

源服务器发送带字段列表的 Vary 可能有两个目的:

  1. 告知缓存接收者, 除非后续请求在所列字段上具有与原始请求相同的值, 否则 MUST NOT 使用此响应来满足后续请求 ([RFC7234] Section 4.1). 换言之, Vary 扩展了将新请求匹配到已存储缓存条目所需的缓存键.

  2. 告知用户代理接收者, 此响应受内容协商 (Section 3.4) 约束, 且如果在所列头部字段中提供附加参数, 后续请求中可能会发送不同表示 (主动协商).

当源服务器选择表示的算法会基于请求消息中除方法和请求目标之外的方面而变化时, 源服务器 SHOULD 发送 Vary 头部字段, 除非这种差异不能跨越, 或源服务器被有意配置为防止缓存透明性. 例如, 无需在 Vary 中发送 Authorization 字段名, 因为跨用户复用已受字段定义约束 ([RFC7235] Section 4.2). 同样, 源服务器可能使用完全处于其控制之内的请求头部字段来选择表示 (例如通过私有头部字段或内部请求元数据), 在这种情况下无需在 Vary 中公布它.

7.2. 验证器头部字段

验证器头部字段传达有关选定表示 (Section 3) 的元数据. 在对安全方法的响应中, 验证器字段描述选定表示. 在对改变状态的方法的响应中, 验证器字段描述成功处理请求后替换先前选定表示的新表示.

7.2.1. ETag

响应中的 "ETag" 头部字段提供选定表示的当前 entity-tag, 该值在请求处理结束时确定. entity-tag 是一个不透明验证器, 用于区分同一资源的多个表示, 无论这些多个表示是由于资源状态随时间变化产生、内容协商导致多个表示同时有效, 还是二者兼有.

ETag = entity-tag

entity-tag 语法在 [RFC7232] Section 2.3 中定义:

entity-tag = [ weak ] opaque-tag
weak = %x57.2F ; "W/", case-sensitive
opaque-tag = DQUOTE *etagc DQUOTE
etagc = %x21 / %x23-7E / obs-text
; VCHAR except double quotes, plus obs-text

注意: 以前, opaque-tag 被定义为 quoted-string ([RFC2616] Section 3.11); 因此, 一些接收者可能执行反斜杠反转义. 因此服务器应避免在 entity tag 中使用反斜杠字符.

entity-tag 可以是弱验证器或强验证器, 默认是强验证器. 如果源服务器为表示提供 entity-tag, 且生成该 entity-tag 的方式不满足强验证器的所有特征 ([RFC7232] Section 2.1), 则源服务器 MUST 通过在其不透明值前加上 "W/" (区分大小写) 将该 entity-tag 标记为弱.

发送者 MAY 在 trailer section ([RFC7230] Section 4.1.2) 中发送 ETag 字段, 但这只对没有内容编码且用户代理能够在收到 trailer section 之前计算 entity-tag 的响应有用. 当 ETag 在 trailer section 中发送时, 它会覆盖在 header section 中发送的任何 ETag 字段值.

示例:

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

对于任何能够合理且一致地检测变化的选定表示, 源服务器 SHOULD 发送 ETag, 因为 entity-tag 在条件请求和评估缓存新鲜度 ([RFC7234]) 中的使用可以大幅减少不必要传输, 并显著提升服务可用性和可扩展性.

7.2.2. Last-Modified

响应中的 "Last-Modified" 头部字段提供一个时间戳, 指示源服务器认为选定表示最后修改的日期和时间, 该值在请求处理结束时确定.

Last-Modified = HTTP-date

其使用示例如下:

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

对于任何能够合理且一致地确定最后修改日期的选定表示, 源服务器 SHOULD 发送 Last-Modified, 因为它在条件请求和评估缓存新鲜度 ([RFC7234]) 中的使用可以大幅减少不必要传输, 并显著提升服务可用性和可扩展性. 一个表示通常是资源接口背后许多部分的总和. last-modified 时间通常会是这些部分中任何一部分最近发生变化的时间.

源服务器 SHOULD 尽可能在接近其为响应生成 Date 字段值的时间获取表示的 Last-Modified 值. 这允许接收者准确评估表示的修改时间, 尤其当表示在响应生成时间附近发生变化时.

具有时钟 (按 Section 7.1.1.1 定义) 的源服务器 MUST NOT 发送晚于服务器消息发起时间 (Date) 的 Last-Modified 日期. 如果最后修改时间来自实现特定元数据, 且根据源服务器时钟求值为未来某个时间, 则源服务器 MUST 用消息发起日期替换该值. 这可以防止未来修改日期对缓存验证产生不利影响.

没有时钟的源服务器 MUST NOT 为响应分配 Last-Modified 值, 除非这些值由某个带时钟的其他系统与资源关联, 或者这些值先前从源服务器收到 (例如来自后端数据库).

7.3. 认证质询

认证质询指示客户端在未来请求中可用于提供认证凭据的机制.

7.3.1. WWW-Authenticate

"WWW-Authenticate" 头部字段指示适用于目标资源的认证方案和参数.

WWW-Authenticate = 1#challenge

生成 401 (Unauthorized) 响应的服务器 MUST 发送包含至少一个 challenge 的 WWW-Authenticate 头部字段. 服务器 MAY 在其他响应消息中生成 WWW-Authenticate 头部字段, 以指示提供凭据 (或不同凭据) 可能会影响响应.

转发响应的代理 MUST NOT 修改该响应中的任何 WWW-Authenticate 字段.

建议用户代理在解析字段值时格外小心, 因为它可能包含多个 challenge, 且每个 challenge 都可以包含逗号分隔的认证参数列表. 此外, 头部字段本身也可以出现多次.

更多细节见 [RFC7235] Section 4.1.

7.3.2. Proxy-Authenticate

"Proxy-Authenticate" 头部字段由至少一个 challenge 组成, 指示适用于此 request-target 的代理的认证方案和参数. 代理在其生成的每个 407 (Proxy Authentication Required) 响应中 MUST 发送至少一个 Proxy-Authenticate 头部字段.

Proxy-Authenticate = 1#challenge

不同于 WWW-Authenticate, Proxy-Authenticate 头部字段只适用于响应链中的下一个出站客户端. 这是因为只有选择给定代理的客户端才可能拥有认证所需凭据. 不过, 当同一管理域内使用多个代理时, 例如大型企业网络中的办公室和区域缓存代理, 常见做法是凭据由用户代理生成并沿层次结构传递直到被消费. 因此, 在这种配置中, 看起来就像 Proxy-Authenticate 正在被转发, 因为每个代理都会发送同一组 challenge.

更多细节见 [RFC7235] Section 4.3.

7.4. 响应上下文

以下响应头部字段提供有关响应的附加信息, 超出状态码所暗示的内容, 或提供有关处理响应的服务器的信息.

7.4.1. Allow

"Allow" 头部字段列出目标资源声明支持的方法集合. 该字段的目的严格限于告知接收者与该资源关联的有效请求方法.

Allow = #method

使用示例:

Allow: GET, HEAD, PUT

实际允许的方法集合由源服务器在每次请求时定义. 源服务器 MUST 在 405 (Method Not Allowed) 响应中生成 Allow 字段, 并 MAY 在任何其他响应中这样做. 空的 Allow 字段值表示该资源不允许任何方法, 如果资源已通过配置临时禁用, 这可能出现在 405 响应中.

代理 MUST NOT 修改 Allow 头部字段 -- 它无需理解所有被指示的方法, 也能按照通用消息处理规则处理它们.

7.4.2. Server

"Server" 头部字段包含有关源服务器用于处理请求的软件的信息. 客户端常使用这些信息帮助识别报告的互操作性问题范围, 绕过或调整请求以避免特定服务器限制, 以及分析服务器或操作系统使用情况. 源服务器 MAY 在任何响应中生成 Server 字段.

Server = product *( RWS ( product / comment ) )

Server 字段值由一个或多个产品标识符组成, 每个标识符后跟零个或多个注释 ([RFC7230] Section 3.2), 它们共同标识源服务器软件及其重要子产品. 按约定, 产品标识符按其对识别源服务器软件的重要性递减列出. 每个产品标识符由名称和可选版本组成, 如 [RFC7230] Section 5.5.3 所定义.

示例:

Server: CERN/3.0 libwww/2.17

源服务器 SHOULD NOT 生成包含不必要细粒度细节的 Server 字段, 并 SHOULD 限制第三方添加子产品. 过长且过于详细的 Server 字段值会增加响应延迟, 并可能揭示内部实现细节, 使攻击者 (略微) 更容易发现和利用已知安全漏洞.