【问题标题】:For which 3xx HTTP codes is the Location header mandatory?对于哪些 3xx HTTP 代码,Location 标头是强制性的?
【发布时间】:2013-04-18 04:20:47
【问题描述】:

RFC 2616Location 标头定义为:

Location 响应头字段用于将接收者重定向到 Request-URI 以外的位置,以完成请求或识别新资源
...
对于 3xx 响应,位置应该指示服务器的首选 URI,以便自动重定向到资源。

AFAIK,对于3xx Redirection 代码,Location 标头是:

  • 300 多项选择:可选
  • 301 永久移动:必需
  • 302 找到:必需
  • 303 查看其他:必需
  • 304 未修改:无关
  • 305 使用代理:不相关 (?)
  • 306 切换代理:不相关 (?)
  • 307 临时重定向:必需
  • 308 永久重定向:必需

但这只是个人经验。是否有定义哪些 HTTP 代码需要发送Location 标头的标准?

也就是说,对于哪些 3xx 代码,HTTP 客户端在接收到没有相应的 Location 标头时应该抛出异常?

【问题讨论】:

  • 实际上,RFC2616 说Location 不需要。对于 301:“新的永久 URI 应该由响应中的位置字段给出。”所以,没有一个?
  • @EdwardThomson 如果你是对的,那很奇怪:如果没有LocationMoved PermanentlyTemporary RedirectPermanent Redirect 怎么可能有意义?
  • 现在这是一个好问题。 :)
  • 我个人看到过这样的响应,但没有提供新的位置。有时是因为资源已经移动,但提供者不再希望人们在没有明确提供位置的情况下直接访问它。至于重定向......好吧,我不知道你为什么不发送位置。我的猜测是没有办法“要求”某些字段,他们能做的最好的事情就是希望实现它的人正确地做到这一点并阅读 RFC。
  • @Benjamin - 我们目前在暂存站点上使用的页面告诉我们的客户“现在请参考生产站点,而不是这个暂存站点。更新您的书签。” .虽然我们可以自动重定向它们,但通过消息通知它们会很有帮助。在这种情况下,我会考虑使用 301 或 302 没有 位置标头,很高兴知道 RFC 推荐 一个但不需要 一个。

标签: http


【解决方案1】:

在 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, section 6.4.1

如果服务器知道资源的多个表示,则返回 300 代码。从 RFC 7231 开始,不再推荐通过RFC 5988 来传达可能表示列表的方法,尽管提到了Link 标头。关于Location 标头,RFC 有这样的说法:

如果服务器有首选,服务器应该生成一个包含首选 URI 引用的 Location 头字段。用户代理可以使用 Location 字段值进行自动重定向。

表示Location 标头仅在服务器具有首选表示形式时使用。如果没有,服务器根本就没有这样的偏好。

值得一提的是,Location 标头本身不适合列出所有可能的表示,因为它的语法是一个不能包含列表的单值字段。因此,

Location: //example.com/a
Location: //example.com/b

未定义。

301: 永久移动 – RFC 7231, section 6.4.2

此响应代码是为了让客户端知道所请求资源的全新位置:后续请求将被定向到 Location 标头中指定的位置。

服务器应该在响应中生成一个 Location 头字段,其中包含新永久 URI 的首选 URI 引用。用户代理可以使用 Location 字段值进行自动重定向。

同样,Location 标头的存在并不是绝对要求。缺少此标题的实用性值得怀疑。语义类似于 - 但不等于 - 410 (Gone) 响应:“此资源已永久移动到一个新的但未知的位置。”

302: 找到 - RFC 7231, section 6.4.3

最初这已被指定为“临时重定向”,并在以后的规范中重命名。与 301 相比,这个不能(或不应该)被缓存或用于永久重写 URL。规范的相关部分如下:

服务器应该在响应中生成一个 Location 头字段,其中包含不同 URI 的 URI 引用。用户代理可以使用 Location 字段值进行自动重定向。

我相信缺少 Location 标头的语义与 301 几乎相同:“此资源已暂时移动到一个新的但未知的位置。”

303:查看其他 - RFC 7231, section 6.4.4

303 应该返回以响应 POST 请求,但适用于任何方法。一般来说,它的目的是让客户端知道在替代 URL 处有更合适的表示,或者请求的资源无法通过 HTTP 传输。

在这个问题的背景下,这有点让人头疼。 RFC 2616, section 10.3.4 状态:

不同的 URI 应该由响应中的 Location 字段给出。

较新的 RFC 7231 的相关部分似乎只是假设存在 Location 标头:

服务器将用户代理重定向到不同的资源,如 Location 标头字段中的 URI 所示

勘误表中没有任何内容可以澄清这一点,因此我倾向于假设 RFC 2616 的位置。缺少的 Location 标头的语义确实因请求方法而异:

304: 未修改 – RFC 7232, section 4.1

此响应在某种程度上很特别,因为它强调“[指示] 用户代理需要采取进一步的行动来满足请求。”应该理解为不是重定向到新的 URI 而是重定向到 to a local cache。在 RFC 7232 的相关部分中根本没有提到 Location 标头。事实上,这对于我的理解来说毫无意义,语义类似于“请求的该实体的表示仍然没有被链接,你会在你的本地缓存中找到它......”这是对关注点分离的极大破坏,但是更不用说Location 在这个地方是不允许的。不过,Content-Location 或带有rel=self 部分的Link 标头更合适。前者得到明确提及:

生成 304 响应的服务器必须生成以下任何标题字段,这些字段将在同一请求的 200 (OK) 响应中发送:Cache-ControlContent-LocationDateETag、@ 987654343@,和Vary

305:使用代理——RFC 2616, section 10.3.6RFC 7231, section 6.4.5

出于安全考虑,自 RFC 7231 起,此状态代码已被弃用(参见 Appendix B)。它在 RFC 2616 中的定义如下:

必须通过 Location 字段给出的代理访问请求的资源。

暗示 Location 标头的存在,但它并没有明确要求它。省略此标头将具有“此资源只能通过 some 代理访问”的语义含义。

306: 切换代理 – draft-cohen-http-305-306-responses-00

该代码是在 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:临时重定向 - RFC 7231, section 6.4.7

307 是由于 HTTP/1.1 中 302 的语义更改而引入的:虽然通过 302 重定向可以更改请求方法,但重定向的请求必须具有与原始请求相同的请求方法。

规范的相关部分如下:

服务器应该在响应中生成一个 Location 头字段,其中包含不同 URI 的 URI 引用。用户代理可以使用 Location 字段值进行自动重定向。

同样,Location 似乎是可选的。对于由于缺少标头而导致的语义变化,请参见 302。

308:永久重定向 - RFC 7538

与 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 已知时才提供位置。否则,客户/用户必须决定下一步该做什么

【讨论】:

  • 感谢您的研究,有问题最终得到解答总是好的 :)
  • @Benjamin:正如我在介绍中所写:在一些较旧的 RFC 和草案中窥探一下很有趣;)此外,它还兼作关于哪些 3xx 代码用于什么角色。
  • 经过深入研究和参考。希望我能多次投票。 :-)
猜你喜欢
  • 2014-02-14
  • 2013-03-12
  • 2014-10-20
  • 2014-04-04
  • 2011-09-14
  • 2011-06-11
  • 2010-10-01
  • 2021-09-23
  • 2013-12-14
相关资源
最近更新 更多