302重定向和307重定向有什么区别?

279

302 FOUND307 TEMPORARY REDIRECT HTTP 响应之间有什么区别?

W3 规范 表明它们都用于临时重定向,并且除非响应明确允许,否则两者都不能被缓存。

10个回答

210

307诞生是因为用户代理采用了一种默认行为,即将收到302响应的POST请求发送到Location响应头的GET请求。

那是不正确的行为——只有303应该导致POST变成GET。 如果原始的POST请求返回302,则用户代理应该(但没有)坚持使用POST方法请求新URL。

307被引入是为了让服务器向用户代理明确表示,在遵循Location响应头时,客户端不应进行方法更改。


3
有哪些用户代理会做出错误的响应?通常来说,这占访问者的非常小的比例。 - makerofthings7
11
@makerofthings7 所有浏览器都错误地处理 302 。Chrome 30、IE10都如此。这成为了事实上的错误实现;由于许多网站错误地发出302,因此无法更改该问题。实际上,ASP.NET MVC 错误地发出302,而这取决于浏览器错误地处理它这一事实。 - Ian Boyd
1
@IanBoyd 框架这样做的唯一原因是因为 303 也是在 HTTP 1.1 规范中与 307 一起引入的,因此允许向后兼容 HTTP 1.0 用户代理。当然,真正的问题是现在我们是否仍然应该处理 HTTP 1.0 用户代理? - ewanm89
1
@ewanm89 看起来框架可以创建正确命名的响应方法(例如 Response.RedirectSeeOther),如果客户端不是 1.1 版本(例如 GET /foo.htmlGET /foo.html HTTP/1.0),则发出传统的 302 - Ian Boyd
重定向时,看起来302 = 303。 - vee

122
这个区别涉及到重定向POSTPUTDELETE请求,以及服务器对用户代理行为的期望(RFC 2616):

注意:RFC 1945和RFC 2068规定客户端不允许在重定向请求上更改方法。然而,大多数现有的用户代理实现将302视为303响应,无论原始请求方法如何,在Location字段值上执行GET。状态码303和307已经添加到这些服务器上,以便清楚地表明客户端期望响应的类型。

此外,请阅读维基百科关于30x重定向代码的文章。

那么,从解析器/代理/浏览器的角度来看,我们可以将302和307视为相同的吗?(我们可以使用完全相同的代码来处理这两种情况,而无需进一步区分吗?) - Pacerier
1
不可以将302和303视为相同,但307是不同的。 - Quentin Skousen
@kkhugs,不可能的,要执行与1.1浏览器中get-307相同的get-302操作,需要使用1.0浏览器。要执行与get-302相同的post-302操作,需要使用1.0浏览器,但必须首先要求用户确认才能继续,并且方法必须是post。 - Pacerier
1
需要使用1.1版本的浏览器来执行get-302,就像执行get-307一样。 - Pacerier

68
一个很好的 307 内部重定向 的例子是当 Google Chrome 遇到一个它知道需要严格传输安全 (Strict Transport Security) 的域名的 HTTP 调用时。浏览器使用与原始调用相同的方法无缝重定向。 HTST 307 Internal Redirect

2
你知道Google什么时候实现了这个功能吗? - Tijme
2
是的,这就是我看到它发生的地方 - 我们的服务器没有发送它 - 在Chrome开发工具中看起来像是,但实际上只是Chrome执行重定向,因为我们有一个Strict Transport Security头。 - mike nelson

58

流程图

  • 301: 永久重定向,该URL已过时并应被替换。 浏览器将缓存此项更改。
    示例用法: URL从/register-form.html移动到signup-form.html
    根据RFC 7231的规定,方法将更改为GET:“由于历史原因,用户代理可以将请求方法从POST更改为GET以进行后续请求。”
  • 302: 临时重定向。仅适用于HTTP / 1.0客户端。 此状态代码不应更改方法,但浏览器已经这样做了。 RFC说:“许多HTTP / 1.1之前的用户代理不了解[303]。当与这些客户端的互用性是一个问题时,可能使用302状态代码,因为大多数用户代理对302响应做出了如下描述。”当然,一些客户端可能会按照规范进行实现,因此如果与这些古老的客户端的互用性不是真正的问题,则303对于一致的结果更好。
  • 303: 临时重定向,将方法更改为GET。
    示例用法: 如果浏览器向/register.php发送POST,则现在加载(GET)/success.html
  • 307: 临时重定向,以相同方式重复请求。
    示例用法: 如果浏览器向/register.php发送了POST请求,那么这会告诉它在/signup.php重新执行POST。
  • 308: 永久重定向,完全重复请求。 307是303的“不更改方法”的版本,而308状态是301的“不更改方法”的版本。

RFC 7231(来自2014年)非常易读且不冗长。如果您想要确切的答案,建议仔细阅读该文档。其他一些答案使用了1999年的RFC2616,但是并没有任何更改。

RFC 7238指定了308状态。虽然它被认为是实验性的,但它已经在2016年得到了所有主流浏览器的支持


2
302 并未被弃用。 - Julian Reschke
2
@JulianReschke 维基百科表示“302已被303和307取代。”也许这是因为我不是母语人士,但在这个上下文中,对我来说,superseded和deprecated的意思是相同的:要么使用303或307,而不是302。我理解错了吗? - Luc
错的是认为维基百科对此有发言权。如果302被弃用,HTTP会说出来的。 - Julian Reschke
1
@JulianReschke 好的,我查看了源代码,你是完全正确的。RFC实际上非常易懂,而且在某些情况下甚至建议使用302状态码。顶部提到的所有“更新者”和“废弃者”RFC都不涉及状态码,所以我想这份1999年的文件确实是我们目前最新的版本。我会更新我的答案。 - Luc
相关的是IANA状态码注册表,因此,在这种情况下,是RFC 7231。 - Julian Reschke
显示剩余3条评论

37

原本只有302

响应浏览器应该做什么
302 Found用新的URL重新发起请求

思路是:

  • 如果你在某个位置进行了GET,则需要使用新的URL重新发起GET请求
  • 如果你在某个位置提交了POST,则需要使用新的URL重新发起POST请求
  • 如果你在某个位置进行了PUT,则需要使用新的URL重新发起PUT请求
  • 如果您在某个位置进行了DELETE,则需要使用新的URL重新发起DELETE请求
  • 等等

不幸的是,所有浏览器都做错了。当收到302时,它们总是会切换到使用GET方法请求新的URL,而不是重试相同的方法(例如POST):

  • Mosaic做错了
  • Netscape复制了Mosaic中的错误;所以他们也做错了
  • Internet Explorer复制了Netscape中的错误;所以他们也做错了

这样就形成了事实上的错误。

所有浏览器都处理302错误。因此,303307被创建了。

响应浏览器应该做什么浏览器实际上做了什么
302 Found用新的URL重新发起请求使用新URL进行GET请求
303 See Other使用新的URL重新发起GET请求使用新URL进行GET请求
307 Temporary Redirect用新的URL重新发起请求使用新的URL重新发起请求

图表形式

5种不同类型的重定向:

╔═══════════╦════════════════════════════════════════════════╗
║           ║                Switch to GET?                  ║
║           ╟────────────────────────┬───────────────────────╢
║ Temporary ║          No            │         Yes           ║
╠═══════════╬════════════════════════╪═══════════════════════╣
║ No        ║ 308 Permanent Redirect │ 301 Moved Permanently ║
╟───────────╟────────────────────────┼───────────────────────╢
║ Yes       ║ 307 Temporary Redirect │ 303 See Other         ║
║           ║ 302 Found (intended)   │ 302 Found (actual)    ║
╚═══════════╩════════════════════════╧═══════════════════════╝

或者:

响应 是否需要更改? 临时的?
301 永久移动 No No
302 找到 (有意) No Yes
302 找到 (实际) 是的 是的
303 查看其他 是的 是的
307 临时重定向 No 是的
308 永久重定向 No No

8

预期的302重定向:重定向使用相同的请求方法POST在NEW_URL上

CLIENT POST OLD_URL -> SERVER 302 NEW_URL -> CLIENT POST NEW_URL

在302、303状态码的情况下,实际操作是将请求方法从POST更改为GET并重定向到NEW_URL

CLIENT POST OLD_URL -> SERVER 302 NEW_URL -> CLIENT GET NEW_URL (redirect uses GET)
CLIENT POST OLD_URL -> SERVER 303 NEW_URL -> CLIENT GET NEW_URL (redirect uses GET)

307的实际情况:重定向使用相同的请求方法POST在NEW_URL上。

CLIENT POST OLD_URL -> SERVER 307 NEW_URL -> CLIENT POST NEW_URL

4
302是临时重定向,由服务器生成,而307是浏览器生成的内部重定向响应。内部重定向意味着浏览器在请求之前会自动地在get请求中将输入的url从http更改为https,因此不会向Internet发送未经安全保护的连接请求。浏览器是否将url更改为https取决于预装在浏览器中的hsts preload列表。您还可以通过在chrome://net-internals/#hsts中输入域名来将支持https的任何站点添加到列表中。另外一个要注意的是网站所有者可以通过填写https://hstspreload.org/的表单将网站域名添加到预加载列表中,以便即使对于每个用户,它也会预安装在浏览器中,尽管我提到您也可以特别为自己执行此操作。
让我用一个例子来解释: 我向http://www.pentesteracademy.com发出了一个get请求,该网站仅支持https,但是由于站点所有者尚未注册它以预安装hsts预加载列表,因此我的浏览器中没有该域名。 request and response headers
不安全版本的网站的GET请求将重定向到安全版本(请参见上图响应中的位置命名的http标头)。
现在,我通过在chrome:// net-internals /#hsts的Add hsts domain表单中添加其域名来将该站点添加到自己的浏览器预加载列表中,这会修改我的Chrome浏览器上的个人预加载列表。请务必选择包括STS选项的子域。
现在让我们看看添加到hsts预加载列表后相同网站的请求和响应。
request and response headers
您可以在响应标头中看到内部重定向307,实际上此响应是由您的浏览器而不是服务器生成的。
此外,HSTS预加载列表可以帮助防止用户访问不安全版本的站点,因为302重定向容易受到中间人攻击。
希望我在某种程度上帮助您更好地了解重定向。

1
307:浏览器内部使用HSTS预加载列表完成的操作正是我想要听到的。感谢您的确认! - krozaine

1
在某些情况下,攻击者可能会滥用307重定向来获取受害者的凭据。
更多信息可以在{{link1:OAuth 2.0 Comprehensive Formal Security Analysis}}的3.1节中找到。
上述论文的作者建议采取以下措施:
修复。与OAuth标准中当前的措辞相反,重定向的确切方法对于OAuth的安全性至关重要,这不是一个实现细节。在HTTP标准(RFC 7231)中,只有303重定向明确定义了删除HTTP POST请求正文的方法。所有其他HTTP重定向状态代码(包括最常用的302)都留给浏览器选择保留POST请求和表单数据的选项。在实践中,浏览器通常将其重写为GET请求,从而丢弃表单数据,但307重定向除外。因此,OAuth标准应要求在上述步骤中使用303重定向以解决此问题。

1

对于服务器管理员而言,值得注意的是,如果使用307重定向,浏览器可能会向用户发出提示。

例如*,Firefox和Opera会要求用户允许重定向,而Chrome、IE和Safari则会透明地执行重定向。

*参见Bulletproof SSL and TLS(第192页)。


这仅适用于不安全的请求,例如POST。 - Julian Reschke

0
307和302之间唯一的区别在于,307保证了在重定向请求时方法和主体不会被更改。对于302,一些旧客户端错误地将方法更改为GET:使用非GET方法和302的行为在Web上是不可预测的,而使用307的行为是可预测的。对于GET请求,它们的行为是相同的。 参考:307临时重定向

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