对于哪些3xx HTTP代码,Location头是必需的?

Ben*_*min 10 http

RFC 2616Location标头定义为:

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

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

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

但这仅仅来自个人经历.是否有定义了HTTP代码的标准要求Location报头被发送?

也就是说,对于哪个3xx代码,HTTP客户端在收到没有相应Location标头的情况下会抛出异常?

DaS*_*rer 10

在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开始,不再使用推荐的方式来传达可能的表示列表,尽管提到了Link通过RFC 5988的标题.关于Location标题,RFC有这样的说法:

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

这意味着Location只有在服务器具有首选表示时才使用标头.如果没有,则服务器根本没有这样的偏好.

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

Location: //example.com/a
Location: //example.com/b
Run Code Online (Sandbox Code Playgroud)

未定义.

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

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

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

同样,Location标题的存在并非绝对要求.没有这个标题将具有可疑的实用性.语义与410(Gone)响应类似 - 但不相等:"此资源已永久移至新的未知位置."

302:发现 - RFC 7231,第6.4.3节

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

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

我相信缺少Location标题的语义与301完全相同:"此资源已暂时移至新的未知位置."

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

假设303响应于POST请求而返回,但是适用于任何方法.通常,它意味着让客户端知道在替代URL处有更合适的表示,或者所请求的资源不能通过HTTP传输.

在这个问题的背景下,这是一个头脑风暴.RFC 2616,第10.3.4节规定:

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

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

服务器正在将用户代理重定向到其他资源,如Location头字段中的URI所示

勘误中没有任何内容可以澄清这一点,因此我倾向于假设RFC 2616的位置.缺少Location标题的语义根据请求方法而有所不同:

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

这种反应在某种程度上是特殊的,因为它强调"[指示]用户代理需要采取进一步的行动才能完成请求." 应该理解为重定向不是新URI而是本地高速缓存.在LocationRFC 7232的相关部分中根本没有提到标题.实际上,对于我的理解,语义就像是"所请求的这个实体的呈现仍然没有链接,你会在你的本地缓存中找到它......"这对于关注点的分离是一个很大的突破,这是没有意义的.不是说Location不允许在这个地方.不过,Content-Location或者Link带有rel=self部件的标题更合适.前者正在接受明确提及:

生成304响应的服务器必须生成以下任何一个头字段,这些字段将在对同一请求的200(OK)响应中发送:Cache-Control,Content-Location,Date,ETag,ExpiresVary.

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

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

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

意味着存在Location标头,但它没有明确要求它.省略此标题将具有"此资源只能通过某个代理访问"的语义含义.

306:Switch Proxy - draft-cohen-http-305-306-responses-00

在RFC 2068最终确定并且已经被RFC 2616废弃之后,这些代码已作为草案引入.据我所知,该草案从未达到推荐的状态,因此这纯粹是为了完整性.该草案的基本原理是为代理提供一种机制,以便将客户端(临时)引导到其他代理以用于后续请求.

该草案的一部分是引入Set-Proxy标题,用于代替2.2节Location标题:

在原始HTTP/1.1规范中,"位置"标头用于指示代理设置.它的使用在305响应的上下文中由'Set-proxy'标头弃用.所有新实现必须发送Set-proxy头.实现可以发送'Location'标题以允许向后兼容.

Set-Proxy然后在306的上下文中需要,而Location标题是纯可选的.由于要求Set-Proxy替换所需的机制Location,后一个头的缺失不会引入语义变化.

307:临时重定向 - RFC 7231,第6.4.7节

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

该规范的相关部分如下:

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

再次,Location似乎是可选的.对于由于缺少标题而导致的语义更改,请参阅302.

308:永久重定向 - RFC 7538

与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的上下文中阅读"SHOULD" :

这个词,或形容词"推荐",意味着在特定情况下可能存在忽略特定项目的正当理由,但在选择不同的课程之前必须理解并仔细权衡全部含义.

这不同于"必须"或"必需"的绝对要求(也在该RFC中).简而言之:没有3xx级代码,其中Location标头是必需的.

应该注意的是,缺少Location标题的问题不是新问题.从另一个答案:

301,302,303和307仅在下一个URL已知时才提供位置.否则,客户端/用户必须决定下一步做什么