HTTP POST应该如何正确处理302重定向到GET?

27

什么是POST => 302重定向到GET所期望的正确行为?

在Chrome(以及可能大多数浏览器)中,当我POST(到一个想要重定向我的资源)并收到302重定向后,浏览器会自动在302位置上发出GET请求。这甚至是知名模式。但是,按照我阅读规范的方式,似乎暗示这不应该发生。

HTTP规范说

如果除GET或HEAD之外的请求收到302状态码,则用户代理不得自动重定向请求,除非可以通过用户确认,因为这可能会更改发出请求的条件。

而Fiddler正在显示:

REQUEST 1: POST URLA
RESPONSE 1: 302 redirect to URLB
REQUEST 2: GET URLB

上面的部分似乎在说浏览器不应该发起GET请求?我错过了什么?

  1. 规范中早期的某些内容使得这一部分不相关。
  2. 我对自动重定向的理解是错误的(而做GET请求的Chrome浏览器实际上并没有真正进行自动重定向)。
  3. 我的理解得到用户的确认。
  4. 其他原因?
3个回答

32
规范中的下一行是:

注意:RFC 1945和RFC 2068指定客户端不允许更改重定向请求的方法。然而,大多数现有的用户代理实现将302视为303响应,无论原始请求方法如何,在Location字段值上执行GET操作。状态码303和307已添加到服务器上,以便使客户端的预期反应变得明确。

紧接着,它解释了如何处理303,这正是您所看到的。
如果您想知道为什么服务器仍在使用302而不是所有现代浏览器都可以正确处理的307,则是因为旧的浏览器无法处理它。如果您想知道为什么浏览器将302视为303,那是因为旧的服务器希望如此。真的没有办法摆脱这个循环,HTTP最好只需将302恢复为它原来的含义,并弃用它(对于非GET/HEAD),转而使用307。

1
abarnet:请澄清您所说的“旧浏览器”是指哪些浏览器。 - Julian Reschke
@JulianReschke:我不确定。如果非要猜的话,我会猜测它的版本大约是IE6和FF 1.9左右。但请记住,桌面浏览器(以及WebKit移动浏览器)并不是唯一的用户代理;还有很多人使用其他设备,在其中运行浏览器、手工编写的Web服务客户端或者爬虫工具等等。 - abarnert
@JulianReschke: 另外,我应该提到303和307仅适用于HTTP/1.1。有很多服务器和缓存(以及一些用户代理)无法处理1.1,或者禁用它。同时,我刚刚找到了IE团队的博客文章,看起来相关。 - abarnert
1
FF 1.9 对我来说似乎不相关。IE6 确实 支持307。归根结底,你总会发现某些客户端是有问题的,所以你需要划清界限。 - Julian Reschke
2
@JulianReschke:我并不是说你的服务器应该滥用302,我只是解释为什么很多服务器仍然这样做。只要所有新的浏览器都正确处理了这个错误行为(而且它们确实做到了),并且有任何需要这种错误行为的旧浏览器,服务器就会继续滥用它。这不是一件好事,但这是一个事实。 - abarnert

3

abarnert是正确的! 我遇到了与Google App Engine相同的问题,但我找到了另一种解决方案。

我的问题是,在前端执行了一个包含表单的POST请求到后端GO formHandler。但它被执行为:

请求 1: GET /formHandler -> 响应 1: 302 Found

请求 2: POST /formHandler -> 响应 2: 302 Found

请求 3: GET /formHandler -> 响应 3: 200 Ok

此外,我收到了:

请求的资源上缺少'Access-Control-Allow-Origin'头信息

这是一个CORS问题。

然而,解决方案是使用HTTPS而不是HTTP。

然后你将会得到:

请求: POST /formHandler -> 响应: 200 Ok


1
你可能需要阅读 http://greenbytes.de/tech/webdav/draft-ietf-httpbis-p2-semantics-22.html#rfc.section.6.4.p.3,它试图澄清这种情况。
注意:在HTTP/1.0中,第一类重定向定义了301(永久移动)和302(找到)状态码([RFC1945],第9.3节)。早期的用户代理程序分为两类,一类是应用于重定向目标的方法与原始请求相同,另一类是重写为GET。尽管HTTP最初定义了301和302的前一种语义(以匹配其在CERN的原始实现),并定义了303(参见其他)来匹配后一种语义,但流行做法逐渐趋于将301和302的语义也改为后一种。HTTP/1.1的第一个修订版添加了307(临时重定向)以指示前一种语义,而不受分歧做法的影响。10多年后,大多数用户代理程序仍然对301和302进行方法重写;因此,当原始请求为POST时,该规范使得这种行为符合要求。

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