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