Skip to main content

7. 响应头字段 (Response Header Fields)

响应头字段允许服务器传递关于响应的额外信息,这些信息超出了状态行中的内容。这些头字段提供关于服务器、对目标资源的进一步访问或相关资源的信息。

尽管每个响应头字段都有定义的含义,但一般来说,其精确的语义可能会被请求方法和/或响应状态码的语义进一步细化。

7.1. 控制数据 (Control Data)

响应头字段可以提供补充状态码的控制数据、指导缓存或指示客户端下一步去向。

7.1.1. 起源日期 (Origination Date)

7.1.1.1. Date

"Date"头字段表示消息产生的日期和时间,具有与[RFC5322]第3.6.1节中定义的起源日期字段(orig-date)相同的语义。字段值是一个HTTP-date,如[RFC7231]第7.1.1.1节所定义。

Date = HTTP-date

示例:

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

当生成Date头字段时,发送者应当(SHOULD)将其字段值生成为消息生成日期和时间的最佳可用近似值。理论上,日期应该表示有效载荷生成之前的时刻。实际上,日期可以在消息产生期间的任何时间生成。

源服务器如果没有能够提供协调世界时(UTC)当前实例的合理近似值的时钟,则禁止(MUST NOT)发送Date头字段。如果响应处于1xx(信息性)或5xx(服务器错误)类别的状态码,源服务器可以(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 ; 过时的RFC 850格式
Sun Nov 6 08:49:37 1994 ; ANSI C的asctime()格式

第一种格式是首选的互联网标准,代表了[RFC5322](第3.3节)定义的固定长度子集。第二种格式普遍使用,但基于过时的RFC 850 [RFC0850]日期格式,并且缺少四位数的年份。解析日期值的HTTP/1.1客户端和服务器必须(MUST)接受所有三种格式(以与HTTP/1.0兼容),尽管它们必须(MUST)只生成IMF-fixdate格式来表示头字段中的HTTP-date值。

注意: rfc850-date格式(使用两位数年份)的时间戳值的接收者,必须(MUST)将看起来在未来超过50年的时间戳解释为表示过去最近的具有相同末两位数字的年份。

HTTP-date值将时间表示为协调世界时(UTC)的实例。前两种格式通过格林威治标准时间的三字母缩写"GMT"(UTC名称的前身)指示UTC;asctime格式中的值被假定为UTC。从本地时钟生成HTTP-date值的发送者应当(ought to)使用NTP([RFC5905])或某种类似协议将其时钟与UTC同步。

首选格式:

HTTP-date    = IMF-fixdate / obs-date

IMF-fixdate = day-name "," SP date1 SP time-of-day SP GMT
; 固定长度/区域/大小写的格式子集
; 参见[RFC5322]第3.3节

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

date1 = day SP month SP year
; 例如,02 Jun 1982

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

GMT = %x47.4D.54 ; "GMT",区分大小写

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

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
; 例如,02-Jun-82

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

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

HTTP-date是区分大小写的。发送者禁止(MUST NOT)在HTTP-date中生成除语法中明确包含的SP之外的额外空白。day-name、day、month、year和time-of-day的语义与为具有相应名称的互联网消息格式构造定义的语义相同([RFC5322],第3.3节)。

7.1.2. Location

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

Location = URI-reference

字段值由单个URI-reference组成。当它具有相对引用的形式时([RFC3986],第4.2节),最终值是通过根据有效请求URI([RFC7230],第5.5节)解析它来计算的。

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

如果3xx(Redirection)响应中提供的Location值没有片段组件,用户代理必须(MUST)将重定向处理为好像该值继承了用于生成请求目标的URI引用的片段组件(即,重定向继承原始引用的片段,如果有的话)。

例如,为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值中的片段标识符是不合适的。例如,201(Created)响应中的Location头字段应该提供特定于创建的资源的URI。

注意: 一些接收者试图从不是有效URI引用的Location字段中恢复。本规范不强制要求或定义这种处理,但为了健壮性而允许它。作为绝对路径的Location字段值是可接受的,但将相对于有效请求URI进行解释。

注意: 响应的内容协商可能导致Location值与有效请求URI不同。如果响应是可缓存的,缓存可以使用该Location值来为响应确定更合适的键(参见[RFC7234]第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字段值表示命名的请求头字段(称为选择请求头字段)可能在选择表示中起作用。潜在的选择请求头字段不限于本规范定义的那些。

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

Vary: accept-encoding, accept-language

表示源服务器可能在选择此响应的内容时使用了请求的Accept-Encoding和Accept-Language字段(或缺少它们)作为决定因素。

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

  1. 通知缓存接收者,它们禁止(MUST NOT)使用此响应来满足后续请求,除非后续请求对列出的字段具有与原始请求相同的值([RFC7234]第4.1节)。换句话说,Vary扩展了将新请求与存储的缓存条目匹配所需的缓存键。

  2. 通知用户代理接收者,此响应受内容协商(第3.4节)的约束,如果在列出的头字段中提供了额外的参数,则可能在后续请求中发送不同的表示(主动协商)。

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

7.2. 验证器头字段 (Validator Header Fields)

验证器头字段传达关于所选表示(第3节)的元数据。在对安全方法的响应中,验证器字段描述所选表示。在对状态改变方法的响应中,验证器字段描述作为成功处理请求的结果已替换先前所选表示的新表示。

7.2.1. ETag

响应中的"ETag"头字段为所选表示提供当前实体标签,如在处理请求结束时确定的。实体标签是用于区分同一资源的多个表示的不透明验证器,无论这些多个表示是由于随时间的资源状态更改、导致多个表示同时有效的内容协商,还是两者兼而有之。

ETag = entity-tag

实体标签语法在[RFC7232]第2.3节中定义:

entity-tag = [ weak ] opaque-tag
weak = %x57.2F ; "W/",区分大小写
opaque-tag = DQUOTE *etagc DQUOTE
etagc = %x21 / %x23-7E / obs-text
; 除双引号外的VCHAR,加上obs-text

注意: 以前,opaque-tag被定义为quoted-string([RFC2616],第3.11节);因此,一些接收者可能执行反斜杠转义。因此,服务器应当(ought to)避免在实体标签中使用反斜杠字符。

实体标签可以是弱验证器或强验证器,默认为强验证器。如果源服务器为表示提供实体标签,并且该实体标签的生成不满足强验证器的所有特征([RFC7232]第2.1节),则源服务器必须(MUST)通过在其不透明值前加上"W/"(区分大小写)来将实体标签标记为弱。

发送者可以(MAY)在尾部(trailer section)([RFC7230]第4.1.2节)中发送ETag字段,但这仅对没有内容编码并且用户代理可以在接收尾部之前计算实体标签的响应有用。当ETag在尾部中发送时,它会覆盖在头部中发送的任何ETag字段值。

示例:

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

对于可以合理且一致地检测到更改的任何所选表示,源服务器应当(SHOULD)发送ETag,因为实体标签在条件请求和评估缓存新鲜度([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])中的使用可以大大减少不必要的传输并显著改善服务可用性和可扩展性。表示通常是资源接口背后许多部分的总和。最后修改时间通常是这些部分中的任何一个被更改的最近时间。

源服务器应当(SHOULD)尽可能接近为响应生成Date字段值的时间获取表示的Last-Modified值。这允许接收者对表示的修改时间进行准确评估,尤其是在表示在生成响应的时间附近发生更改的情况下。

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

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

7.3. 认证挑战 (Authentication Challenges)

认证挑战指示客户端在未来请求中提供认证凭证可用的机制。

7.3.1. WWW-Authenticate

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

WWW-Authenticate = 1#challenge

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

转发响应的代理禁止(MUST NOT)修改该响应中的任何WWW-Authenticate字段。

建议用户代理在解析字段值时特别小心,因为它可能包含多个挑战,并且每个挑战可以包含逗号分隔的认证参数列表。此外,头字段本身可以多次出现。

更多详细信息,请参见[RFC7235]第4.1节。

7.3.2. Proxy-Authenticate

"Proxy-Authenticate"头字段由至少一个挑战组成,该挑战指示适用于此请求目标的代理的认证方案和参数。对于它生成的每个407(Proxy Authentication Required)响应,代理必须(MUST)发送至少一个Proxy-Authenticate头字段。

Proxy-Authenticate = 1#challenge

与WWW-Authenticate不同,Proxy-Authenticate头字段仅适用于响应链上的下一个出站客户端。这是因为只有选择了给定代理的客户端才可能具有认证所需的凭证。但是,当在同一管理域内使用多个代理时,例如大型企业网络内的办公室和区域缓存代理,用户代理生成凭证并通过层次结构传递直到被消费是常见的。因此,在这种配置中,看起来好像Proxy-Authenticate正在被转发,因为每个代理都将发送相同的挑战集。

更多详细信息,请参见[RFC7235]第4.3节。

7.4. 响应上下文 (Response Context)

以下响应头字段提供关于响应的额外信息,超出状态码所暗示的内容,或关于处理响应的服务器的信息。

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]第3.2节),它们共同标识源服务器软件及其重要子产品。按照惯例,产品标识符按其对识别源服务器软件的重要性递减的顺序列出。每个产品标识符由名称和可选版本组成,如[RFC7230]第5.5.3节所定义。

示例:

Server: CERN/3.0 libwww/2.17

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