这个问题是在 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,不再建议使用任何一种通信可能表示的列表的方式,尽管通过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(已删除)响应:“此资源已永久移动到新位置,但位置未知。”
最初,此状态码被指定为“临时重定向”,并在后续规范中更名。与301相比,此状态码不能(或不应)被缓存或用于永久重写URL。规范的相关部分如下:
服务器应该在响应中生成一个Location头字段,其中包含不同URI的URI引用。用户代理可以使用Location字段值进行自动重定向。
我认为,如果缺少 Location
头,则其语义与301几乎相同:“此资源已暂时移动到新位置,但尚未知道其位置。”
响应POST
请求时应返回303状态码,但适用于任何方法。一般来说,它的作用是让客户端知道在替代URL或无法通过HTTP传输所请求的资源时存在更合适的表示。
在这个问题的背景下,这有点令人费解。RFC 2616, section 10.3.4指出:
不同的URI应在响应中的Location字段中给出。
较新的RFC 7231的相关部分似乎只是假定了Location
头部字段存在:
服务器将用户代理重定向到不同的资源,如Location头字段中指示的URI所示。
没有关于此的勘误说明,因此我倾向于采用RFC 2616的立场。缺少Location
头部字段的语义因请求方法而异:
这个响应有点特殊,因为它强调了“[提示]用户代理需要进一步采取措施以完成请求”。应该理解为重定向到本地缓存
而不是到新的URI。RFC 7232的相关部分中根本没有提到
Location
头部。实际上,据我所知,这样做毫无意义,因为语义是“此实体的请求表示保持不变,并且您将在本地缓存中找到它...”这将会对关注点分离造成巨大的破坏,但并不意味着在这个地方不允许使用
Location
。仍然,
Content-Location
或包含
rel=self
部分的
Link
头更加合适。前者受到明确提及:
服务器生成304响应时必须生成以下任意一个响应头,这些响应头本应在同一请求的
200 (OK)响应中发送:
Cache-Control、
Content-Location、
Date、
ETag、
Expires和
Vary。
由于安全问题(参见附录B),此状态码已在RFC 7231中被弃用。其在RFC 2616中的定义如下:
请求的资源必须通过Location字段给出的代理访问。
这意味着存在一个Location头,但它并没有明确要求。省略此头将具有“此资源只能通过某个代理访问”的语义含义。
在 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已知时提供位置信息。否则,客户端/用户必须决定下一步该怎么做。
Location
是不必需的。对于301:“新的永久URI应该在响应中由Location字段给出。”那么,两者都不需要? - Edward Thomson