哪些3xx HTTP状态码需要强制使用Location响应头?

14

RFC 2616Location响应头定义为:

用于重定向请求的接收者到不同于请求URI的位置,以完成请求或标识新资源
...
对于3xx响应,应该指示位置到服务器的首选URI以自动重定向到资源。

据我所知,对于3xx重定向代码,Location头如下:

  • 300多种选择:可选
  • 301永久移动:必需
  • 302找到:必需
  • 303参见其他:必需
  • 304未修改:无关紧要
  • 305使用代理:无关紧要(?)
  • 306开关代理:无关紧要(?)
  • 307临时重定向:必需
  • 308永久重定向:必需

但这仅基于个人经验。是否有一种标准来定义哪些HTTP代码需要发送Location头呢?

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


实际上,RFC2616指出Location必需的。对于301:“新的永久URI应该在响应中由Location字段给出。”那么,两者都不需要? - Edward Thomson
1
如果你是对的,那很奇怪:没有“位置”,如何理解“永久移动”、“临时重定向”或“永久重定向”? - BenMorel
那真是个好问题。 :) - Edward Thomson
1
我个人见过这样的响应,没有提供新的位置。有时是因为资源已经移动,但提供者不再希望人们直接访问它,除非他们明确给出位置。至于重定向...我不知道为什么你不会发送位置。我猜想可能没有一种“要求”特定字段的方法,他们所能做的最好的就是希望实现它的人正确地执行并阅读RFC。 - sanpaco
@Benjamin - 我们目前在演示站点上使用了一个页面,告诉我们的客户“请现在参考生产站点,而不是这个演示站点。更新你的书签。”虽然我们可以自动重定向他们,但通过消息通知他们可能会更有帮助。在这种情况下,我会考虑使用301或302 没有位置头,所以很好知道RFC 建议一个但不要求一个。 - Simon East
1个回答

19

这个问题是在 RFC 2616 仍然是权威标准的时代被提出的,现在 RFC 7230 到 7235 已经取代了它,所以这看起来像是一个有趣的研究项目。那么,让我们看看我们得到了什么。

Location 头现在在 RFC 7231,第7.1.2节 中定义:

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

[...]

对于 201 (已创建) 响应,Location 值指的是由请求创建的主要资源。对于 3xx(重定向)响应,Location 值指的是自动重定向请求的首选目标资源。

这一部分并不仅限于3xx状态码。实际上,唯一明确提到的状态码是201(已创建)和303(参见其他)。没有任何关于该标头实际上被任何状态码“要求”的说法。

现在RFC 7231,第6.4节描述了3xx代码范围的目的:

状态码3xx(重定向)类表明用户代理需要采取进一步的操作才能满足请求。 如果提供了Location标头字段,则用户代理可以自动将其请求重定向到Location字段值引用的URI,即使不理解特定状态码。

措辞表明,无论存在与否,也不强制执行自动重定向到其内容。

在撰写本文时,IANA HTTP状态码注册表列出了300到308的代码已注册。其中一个(305)已过时,一个被保留(306),这留下了七个活动代码:

300:多种选择 - RFC 7231,第6.4.1节

如果服务器知道资源的多个表示形式,则应返回300代码。根据RFC 7231,不再建议使用任何一种通信可能表示的列表的方式,尽管通过RFC 5988Link标头被提及。关于Location标头,RFC中有这样的说法:

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

意味着只有当服务器有首选表示时才使用Location头。如果没有,则服务器根本没有此类偏好。

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

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

未定义。

301: 永久移动 - RFC 7231,第6.4.2节

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

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

同样,Location头的存在并非绝对要求。缺少此标头将具有可疑的实用性。语义类似于但不等于410(已删除)响应:“此资源已永久移动到新位置,但位置未知。”

302:找到 – RFC 7231,第6.4.3节

最初,此状态码被指定为“临时重定向”,并在后续规范中更名。与301相比,此状态码不能(或不应)被缓存或用于永久重写URL。规范的相关部分如下:

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

我认为,如果缺少 Location 头,则其语义与301几乎相同:“此资源已暂时移动到新位置,但尚未知道其位置。”

303:参见其他 – RFC 7231,第6.4.4节

响应POST请求时应返回303状态码,但适用于任何方法。一般来说,它的作用是让客户端知道在替代URL或无法通过HTTP传输所请求的资源时存在更合适的表示。

在这个问题的背景下,这有点令人费解。RFC 2616, section 10.3.4指出:

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

较新的RFC 7231的相关部分似乎只是假定了Location头部字段存在:

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

没有关于此的勘误说明,因此我倾向于采用RFC 2616的立场。缺少Location头部字段的语义因请求方法而异:

304:未修改 - RFC 7232,第4.1节

这个响应有点特殊,因为它强调了“[提示]用户代理需要进一步采取措施以完成请求”。应该理解为重定向到本地缓存而不是到新的URI。RFC 7232的相关部分中根本没有提到Location头部。实际上,据我所知,这样做毫无意义,因为语义是“此实体的请求表示保持不变,并且您将在本地缓存中找到它...”这将会对关注点分离造成巨大的破坏,但并不意味着在这个地方不允许使用Location。仍然,Content-Location或包含rel=self部分的Link头更加合适。前者受到明确提及:
服务器生成304响应时必须生成以下任意一个响应头,这些响应头本应在同一请求的200 (OK)响应中发送:Cache-ControlContent-LocationDateETagExpiresVary

305: 使用代理 – RFC 2616, 第10.3.6节; RFC 7231, 第6.4.5节

由于安全问题(参见附录B),此状态码已在RFC 7231中被弃用。其在RFC 2616中的定义如下:

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

这意味着存在一个Location头,但它并没有明确要求。省略此头将具有“此资源只能通过某个代理访问”的语义含义。

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

在 RFC 2068 完成并已被 RFC 2616 废弃后,此代码作为草案被引入。据我所知,这个草案从未达到建议的状态,所以这只是为了完整性而存在。该草案的原理是为代理提供一种机制,用于将客户端(暂时)重定向到其他代理以进行后续请求。

该草案的一部分是引入 Set-Proxy 标头,该标头应替代 Location 标头,详见 第2.2节

在HTTP/1.1规范的最初版本中,“Location”标头用于指示代理设置。在305响应的上下文中,“Set-proxy”标头已经取代了“Location”标头,因此使用“Location”标头是不推荐的。所有新的实现都必须发送“Set-proxy”标头。为了保证向后兼容性,实现可以选择发送“Location”标头。
在306的情况下,“Set-Proxy”是必需的,而“Location”标头则完全是可选的。由于所需的“Set-Proxy”机制旨在替换“Location”,因此缺少后者标头不会引入语义变化。
307:临时重定向 - RFC 7231,第6.4.7节 307是由于HTTP / 1.1中302的语义更改而引入的:虽然通过302进行的重定向可以更改请求方法,但重定向请求必须具有与原始请求相同的请求方法。
规范的相关部分如下:
服务器应该在响应中生成一个包含不同URI的URI引用的Location头字段。用户代理可以使用Location字段值进行自动重定向。
同样,Location似乎是可选的。有关由于缺少标头而导致的语义更改,请参见302。
308:永久重定向-RFC 7538 与307一样,通过308重定向需要保留其原始请求方法。人们可以说,308对301的作用就像307对302的作用一样。
从规范的第3节中:
服务器应该在响应中生成一个包含新永久URI的首选URI引用的Location头字段。
因此,总之我们有这种情况:
  • 隐含:1(305)
  • 可选:1(306)
  • 未提及:1(304)
  • 应该:6(300;301;302;303;307;308)

“SHOULD”应该在RFC 2119的上下文中阅读:

这个词或形容词“推荐”意味着在特定情况下可能存在有效的理由来忽略特定项目,但必须在选择不同的课程之前充分了解和仔细权衡全部含义。

这与“MUST”或“REQUIRED”(也在该RFC中)的绝对要求不同。简而言之:没有3xx级代码需要“位置”头。

值得注意的是,缺少“位置”头的问题并不新鲜。来自另一个答案

301、302、303和307仅在下一个URL已知时提供位置信息。否则,客户端/用户必须决定下一步该怎么做。

感谢您的研究,总是很好地回答问题 :) - BenMorel
@Benjamin:正如我在介绍中写的一样:研究一些旧的 RFC 和草案非常有趣;同时,它也可以作为一个小概述,说明使用哪些 3xx 代码来扮演什么角色。 - DaSourcerer
1
精心研究和引用,希望我可以多次点赞。 :-) - Simon East

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接