在 RFC 2616 仍然是权威的日子里,这个问题已经被问到了,所以现在 RFC 7230 到 7235 已经到位,这看起来像是一个有趣的研究项目。那么,让我们看看我们在这里得到了什么。
标Location
头现在在RFC 7231 第 7.1.2 节中定义:
在某些响应中使用“Location”标头字段来引用与响应相关的特定资源。关系类型由请求方法和状态码语义组合定义。
[…]
对于201(已创建)响应,位置值是指请求创建的主要资源。对于 3xx(重定向)响应,Location 值是指用于自动重定向请求的首选目标资源。
该部分不将此标头仅限制为状态代码的 3xx 范围。事实上,唯一明确提到的状态代码是 201 (Created) 和303 (See Other)。但是,没有任何状态代码实际需要此标头的消息。
RFC 7231 第 6.4 节现在描述了 3xx 范围代码的用途:
3xx(重定向)类状态码表示用户代理需要采取进一步的行动来满足请求。 如果提供了 Location 头字段,用户代理可以自动将其请求重定向到 Location 字段值所引用的 URI,即使不理解特定的状态代码。
该措辞表明,存在或自动重定向到其内容都不是强制性的。
在撰写本文时,IANA HTTP 状态代码注册表将代码 300 到 308 列为已注册。一个(305)被废弃,一个被保留(306),剩下七个活动代码:
如果服务器知道资源的多个表示,则返回 300 代码。从 RFC 7231 开始,不再推荐Link
通过RFC 5988的标头来传达可能的表示列表的方法。关于Location
标头,RFC 有这样的说法:
如果服务器有首选,服务器应该生成一个包含首选 URI 引用的 Location 头字段。用户代理可以使用 Location 字段值进行自动重定向。
这意味着Location
仅当服务器具有首选表示时才使用标头。如果没有,服务器根本没有这样的偏好。
值得一提的是,Location
标题本身不适合列出所有可能的表示,因为它的语法是一个不能包含列表的单值字段。因此,
Location: //example.com/a
Location: //example.com/b
未定义。
此响应代码是为了让客户端知道所请求的资源有一个全新的位置:后续请求将被定向到Location
标头中指定的位置。
服务器应该在响应中生成一个 Location 头字段,其中包含新永久 URI 的首选 URI 引用。用户代理可以使用 Location 字段值进行自动重定向。
同样,Location
标题的存在不是绝对要求。缺少此标题的实用性值得怀疑。语义类似于 - 但不等于 - 410 (Gone)响应:“此资源已永久移动到一个新的但未知的位置。”
最初这已被指定为“临时重定向”并在以后的规范中重命名。与 301 相比,这个不能(或不应该)被缓存或用于永久重写 URL。规范的相关部分内容如下:
服务器应该在包含不同 URI 的 URI 引用的响应中生成 Location 头字段。用户代理可以使用 Location 字段值进行自动重定向。
我相信缺少Location
标头的语义与 301 几乎相同:“此资源已暂时移动到一个新的但未知的位置。”
303 应该响应POST
请求而返回,但适用于任何方法。一般来说,它的目的是让客户端知道在替代 URL 处有更合适的表示,或者请求的资源无法通过 HTTP 传输。
在这个问题的背景下,这有点让人头疼。RFC 2616,第 10.3.4 节指出:
不同的 URI 应该由响应中的 Location 字段给出。
较新的 RFC 7231 的相关部分似乎只是假设Location
存在标头:
服务器将用户代理重定向到不同的资源,如 Location 标头字段中的 URI 所示
勘误表中没有任何内容可以澄清这一点,因此我倾向于假设 RFC 2616 的位置。缺少Location
标头的语义确实因请求方法而异:
这个响应在某种程度上是特别的,因为它强调“[indication] 用户代理需要采取进一步的行动来满足请求。” 它应该被理解为不是重定向到新的 URI 而是重定向到本地缓存。Location
RFC 7232 的相关部分根本没有提到标头。事实上,这对于我的理解来说意义不大,语义类似于“请求的该实体的表示仍然没有链接,你会在本地缓存中找到它......”这是对关注点分离的极大破坏,但是并不是说Location
在这个地方不允许。仍然,Content-Location
或者Link
带有rel=self
部分的标题更合适。前一个正在接受明确的提及:
生成 304 响应的服务器必须生成以下任何一个头字段,这些字段将在对同一请求的200(OK)响应中发送:Cache-Control、Content-Location、Date、ETag、Expires和Vary。
出于安全考虑,从 RFC 7231 开始不推荐使用此状态代码(参见附录 B)。它在 RFC 2616 中的定义如下:
请求的资源必须通过 Location 字段给出的代理访问。
这意味着存在Location
标头,但它没有明确要求它。省略此标头将具有“此资源只能通过某些代理访问”的语义含义。
该代码是在 RFC 2068 最终确定并已被 RFC 2616 淘汰后作为草案引入的。据我所知,该草案从未达到推荐的状态,所以这纯粹是为了完整性。该草案的基本原理是为代理提供一种机制,以将客户(临时)引导到其他代理以进行后续请求。
该草案的一部分是引入了Set-Proxy
标题,该标题将用于代替第 2.2 节Location
中的标题:
在最初的 HTTP/1.1 规范中,“Location”标头用于指示代理设置。在 305 响应的上下文中,“Set-proxy”标头已弃用它的使用。所有新的实现必须发送 Set-proxy 标头。实现可以发送 'Location' 标头以允许向后兼容。
Set-Proxy
然后在 306 的上下文中是必需Location
的,而标题纯粹是可选的。由于所需的Set-Proxy
机制旨在替换Location
,因此缺少后一个标头不会引入语义更改。
307 是由于 HTTP/1.1 中 302 的语义更改而引入的:虽然通过 302 重定向可以更改请求方法,但重定向的请求必须具有与原始请求相同的请求方法。
规范的相关部分内容如下:
服务器应该在包含不同 URI 的 URI 引用的响应中生成 Location 头字段。用户代理可以使用 Location 字段值进行自动重定向。
同样,Location
似乎是可选的。对于由于缺少标头而导致的语义变化,请参见 302。
与 307 一样,通过 308 进行的重定向将保留其原始请求方法。可以说 308 对 301 就像 307 对 302 一样。
从规范的第 3 节:
服务器应该在响应中生成一个 Location 头字段,其中包含新永久 URI 的首选 URI 引用。
所以,总而言之,我们遇到了这种情况:
- 隐含:1 (305)
- 可选:1 (306)
- 未提及:1 (304)
- 应该:6(300;301;302;303;307;308)
“应该”将在RFC 2119的上下文中阅读:
这个词或形容词“推荐”意味着在特定情况下可能存在忽略特定项目的正当理由,但在选择不同的课程之前必须理解并仔细权衡全部含义。
这与“必须”或“需要”(也在该 RFC 中)的绝对要求不同。简而言之:没有 3xx 类代码中的Location
标头是强制性的。
需要注意的是,缺少Location
标头的问题并不是一个新问题。从另一个答案:
301、302、303 和 307 仅在下一个 URL 已知时才提供位置。否则,客户/用户必须决定下一步做什么