跳到主要内容

10. 消息上下文

10.1. 请求上下文字段

以下请求头字段提供关于请求上下文的附加信息, 包括关于用户, 用户代理以及请求背后资源的信息.

10.1.1. Expect

请求中的 "Expect" 头字段指示服务器为了正确处理该请求而需要支持的一组特定行为 (expectations).

Expect =      #expectation
expectation = token [ "=" ( token / quoted-string ) parameters ]

Expect 字段值不区分大小写.

本规范定义的唯一 expectation 是 "100-continue" (没有定义参数).

收到包含 100-continue 以外成员的 Expect 字段值时, 服务器可以用 417 (Expectation Failed) 状态码响应, 以指示该意外 expectation 无法满足.

"100-continue" expectation 告知接收方, 客户端即将在此请求中发送 (可能很大的) 内容. 如果方法, 目标 URI 和头字段尚不足以导致立即成功, 重定向或错误响应, 客户端希望先收到一个 100 (Continue) 临时响应. 这允许客户端在实际发送内容之前等待一个指示, 用于判断发送内容是否值得. 当数据很大, 或客户端预期很可能发生错误时 (例如, 首次发送会改变状态的方法, 且此前没有已验证的认证凭据), 这可以提升效率.

例如, 以下请求开头:

PUT /somewhere/fun HTTP/1.1
Host: origin.example.com
Content-Type: video/h264
Content-Length: 1234567890987
Expect: 100-continue

允许源服务器在客户端开始用不必要的数据传输填满管道之前, 立即用错误消息响应, 如 401 (Unauthorized) 或 405 (Method Not Allowed).

客户端要求:

  • 客户端不得在不包含内容的请求中生成 100-continue expectation.
  • 如果客户端会在发送请求内容之前等待 100 (Continue) 响应, 则必须发送包含 100-continue expectation 的 Expect 头字段.
  • 发送 100-continue expectation 的客户端不要求等待任何特定时长; 即使尚未收到响应, 这样的客户端也可以继续发送内容. 此外, 由于 100 (Continue) 响应无法通过 HTTP/1.0 中间方发送, 这样的客户端不应在发送内容之前无限期等待.
  • 如果客户端在包含 100-continue expectation 的请求响应中收到 417 (Expectation Failed) 状态码, 则应当在不带 100-continue expectation 的情况下重复该请求, 因为 417 响应仅表示响应链不支持 expectations (例如, 它经过了 HTTP/1.0 服务器).

服务器要求:

  • 服务器收到 HTTP/1.0 请求中的 100-continue expectation 时, 必须忽略该 expectation.
  • 如果服务器已经收到对应请求的部分或全部内容, 或者定帧表明没有内容, 则服务器可以省略发送 100 (Continue) 响应.
  • 发送 100 (Continue) 响应的服务器, 在收到并处理请求内容后, 最终必须发送一个最终状态码, 除非连接过早关闭.
  • 如果服务器在读取完整请求内容之前以最终状态码响应, 则应当指示它是打算关闭连接 (例如, 参见 [HTTP/1.1] 的 Section 9.6), 还是继续读取请求内容.

当源服务器收到 HTTP/1.1 (或更高版本) 请求, 该请求具有方法, 目标 URI 和完整的头部区段, 其中包含 100-continue expectation 且指示后续会有请求内容时, 源服务器必须发送以下二者之一:

  • 如果仅检查方法, 目标 URI 和头字段即可确定状态, 则立即发送带最终状态码的响应; 或
  • 立即发送 100 (Continue) 响应, 以鼓励客户端发送请求内容.

源服务器不得在发送 100 (Continue) 响应之前等待内容.

当代理收到 HTTP/1.1 (或更高版本) 请求, 该请求具有方法, 目标 URI 和完整的头部区段, 其中包含 100-continue expectation 且指示后续会有请求内容时, 代理必须执行以下二者之一:

  • 如果仅检查方法, 目标 URI 和头字段即可确定状态, 则立即发送带最终状态码的响应; 或
  • 通过向下一个入站服务器发送对应的 request-line 和头部区段, 将请求转发给源服务器.

如果代理认为 (根据配置或过去的交互) 下一个入站服务器只支持 HTTP/1.0, 则代理可以生成一个立即的 100 (Continue) 响应, 以鼓励客户端开始发送内容.

10.1.2. From

"From" 头字段包含控制发起请求的用户代理的人类用户的 Internet 电子邮件地址. 该地址应当可由机器使用, 如 [RFC5322] Section 3.4 中 "mailbox" 所定义:

From    = mailbox

mailbox = <mailbox, see [RFC5322], Section 3.4>

示例:

From 头字段很少由非机器人用户代理发送. 用户代理不应在没有用户显式配置的情况下发送 From 头字段, 因为这可能与用户的隐私利益或其站点的安全策略冲突.

机器人用户代理应当发送有效的 From 头字段, 以便在服务器上发生问题时联系负责运行该机器人的人员, 例如机器人正在发送过量, 不想要或无效的请求.

服务器不应将 From 头字段用于访问控制或认证, 因为预期任何接收或观察该请求的人都能看到它的值, 而且它经常被记录在日志文件和错误报告中, 并不存在任何隐私预期.

10.1.3. Referer

"Referer" [sic] 头字段允许用户代理指定一个 URI 引用, 表示目标 URI 是从哪个资源获得的 (即 "referrer", 尽管字段名拼写错误). 用户代理在生成 Referer 字段值时, 不得包含 URI 引用 [URI] 的 fragment 和 userinfo 组成部分 (如果有).

Referer = absolute-URI / partial-URI

字段值要么是 absolute-URI, 要么是 partial-URI. 在后一种情况下 (Section 4), 被引用的 URI 相对于目标 URI ([URI], Section 5).

Referer 头字段允许服务器为简单分析, 日志记录, 优化缓存等生成指向其他资源的反向链接. 它还允许发现过时或输错的链接以便维护. 一些服务器使用 Referer 头字段作为拒绝来自其他站点链接 (所谓 "deep linking") 或限制跨站请求伪造 (CSRF) 的手段, 但并非所有请求都包含它.

示例:

Referer: http://www.example.org/hypertext/Overview.html

如果目标 URI 是从没有自身 URI 的来源获得的 (例如, 用户键盘输入, 或用户书签/收藏夹中的条目), 用户代理必须要么排除 Referer 头字段, 要么发送值为 "about:blank" 的 Referer 头字段.

Referer 头字段值不需要传达引用资源的完整 URI; 用户代理可以截断引用 origin 之外的部分.

Referer 头字段可能泄露关于请求上下文或用户浏览历史的信息. 如果引用资源的标识符泄露个人信息 (如账户名), 或泄露本应保密的资源 (如位于防火墙之后或安全服务内部的资源), 这会带来隐私问题. 大多数通用用户代理在引用资源是本地 "file" 或 "data" URI 时不会发送 Referer 头字段. 如果引用资源是使用安全协议访问的, 且请求目标的 origin 与引用资源的 origin 不同, 用户代理不应发送 Referer 头字段, 除非引用资源明确允许发送 Referer. 如果引用资源是使用安全协议访问的, 用户代理不得在不安全的 HTTP 请求中发送 Referer 头字段. 其他安全考虑事项见 Section 17.9.

已知有些中间方会不加区分地从出站请求中移除 Referer 头字段. 这样做有一个不幸的副作用: 会干扰对 CSRF 攻击的防护, 而这对其用户可能危害更大. 希望限制 Referer 中信息披露的中间方和用户代理扩展, 应当将更改限制为特定编辑, 例如用假名替换内部域名, 或截断 query 和/或 path 组成部分. 当字段值与目标 URI 共享相同的 scheme 和 host 时, 中间方不应修改或删除 Referer 头字段.

10.1.4. TE

"TE" 头字段描述客户端关于传输编码和 trailer sections 的能力.

如 Section 6.5 所述, 在请求中发送带有 "trailers" 成员的 TE 字段, 表示客户端不会丢弃 trailer fields.

TE 在 HTTP/1.1 中还用于告知服务器, 客户端能够在响应中接受哪些传输编码. 截至发布时, 只有 HTTP/1.1 使用传输编码 (见 [HTTP/1.1] 的 Section 7).

TE 字段值是一个成员列表, 其中每个成员 (除 "trailers" 外) 由一个传输编码名称 token 组成, 可以带一个可选 weight 用于指示客户端对该传输编码的相对偏好 (Section 12.4.2), 以及该传输编码的可选参数.

TE                 = #t-codings
t-codings = "trailers" / ( transfer-coding [ weight ] )
transfer-coding = token *( OWS ";" OWS transfer-parameter )
transfer-parameter = token BWS "=" BWS ( token / quoted-string )

TE 的发送方还必须在 Connection 头字段 (Section 7.6.1) 中发送一个 "TE" connection option, 以告知中间方不要转发此字段.

10.1.5. User-Agent

"User-Agent" 头字段包含关于发起请求的用户代理的信息. 服务器经常使用它来帮助识别所报告互操作性问题的范围, 绕过或定制响应以避免特定用户代理限制, 以及分析浏览器或操作系统使用情况. 除非被专门配置为不这样做, 用户代理应当在每个请求中发送 User-Agent 头字段.

User-Agent = product *( RWS ( product / comment ) )

User-Agent 字段值由一个或多个产品标识符组成, 每个标识符后跟零个或多个注释 (Section 5.6.5), 它们共同标识用户代理软件及其重要子产品. 按照约定, 产品标识符按其对识别用户代理软件的重要性降序列出. 每个产品标识符由名称和可选版本组成.

product         = token ["/" product-version]
product-version = token

发送方应当将生成的产品标识符限制为识别产品所必需的信息; 发送方不得在产品标识符中生成广告或其他非必要信息. 发送方不应在 product-version 中生成并非版本标识符的信息 (即, 同一产品名称的连续版本应当只在产品标识符的 product-version 部分有所不同).

示例:

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

用户代理不应生成包含不必要细粒度细节的 User-Agent 头字段, 并且应当限制第三方添加子产品. 过长且详细的 User-Agent 字段值会增加请求延迟, 并增加用户在违背其意愿的情况下被识别的风险 ("fingerprinting").

同样, 不鼓励实现使用其他实现的 product tokens 来声明与其兼容, 因为这会规避该字段的目的. 如果用户代理伪装成另一个用户代理, 接收方可以假定用户有意希望看到为该被标识用户代理定制的响应, 即使这些响应对于实际使用的用户代理可能效果不佳.

10.2. 响应上下文字段

以下响应头字段提供关于响应的附加信息, 超出状态码所隐含的信息, 包括关于服务器, 目标资源或相关资源的信息.

10.2.1. Allow

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

Allow = #method

使用示例:

Allow: GET, HEAD, PUT

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

代理不得修改 Allow 头字段 -- 它不需要理解所有被指示的方法, 也可以按照通用消息处理规则处理它们.

10.2.2. Location

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

Location = URI-reference

字段值由单个 URI-reference 组成. 当它具有相对引用的形式时 ([URI], Section 4.2), 最终值通过相对于目标 URI 解析得到 ([URI], Section 5).

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

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

例如, 为 URI 引用 "http://www.example.org/~tim" 生成的 GET 请求可能得到一个包含以下头字段的 303 (See Other) 响应:

Location: /People.html#tim

这表示用户代理重定向到 "http://www.example.org/People.html#tim".

同样, 为 URI 引用 "http://www.example.org/index.html#larry" 生成的 GET 请求可能得到一个包含以下头字段的 301 (Moved Permanently) 响应:

Location: http://www.example.net/index.html

这表示用户代理重定向到 "http://www.example.net/index.html#larry", 并保留原始 fragment 标识符.

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

Note: 有些接收方会尝试从不是有效 URI 引用的 Location 头字段中恢复. 本规范不强制也不定义这种处理, 但为了健壮性允许这样做. Location 字段值不能允许成员列表, 因为逗号列表分隔符是 URI-reference 中的有效数据字符. 如果一个无效消息带有多个 Location 字段行被发送, 路径上的接收方可能会把这些字段行合并为一个值. 从这种情况中恢复有效的 Location 字段值很困难, 且无法跨实现互操作.

Note: Content-Location 头字段 (Section 8.7) 与 Location 不同, 因为 Content-Location 引用的是与所封装表示对应的最具体资源. 因此, 一个响应可能同时包含 Location 和 Content-Location 头字段.

10.2.3. Retry-After

服务器发送 "Retry-After" 头字段, 用于指示用户代理在发起后续请求之前应当等待多久. 当它随 503 (Service Unavailable) 响应发送时, Retry-After 指示预计服务对客户端不可用的时长. 当它随任何 3xx (Redirection) 响应发送时, Retry-After 指示要求用户代理在发出重定向请求之前至少等待的时间.

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 分钟.

10.2.4. Server

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

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

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

示例:

Server: CERN/3.0 libwww/2.17

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