302 和 307 重定向有啥区别?
Posted
技术标签:
【中文标题】302 和 307 重定向有啥区别?【英文标题】:What's the difference between a 302 and a 307 redirect?302 和 307 重定向有什么区别? 【发布时间】:2011-01-05 07:42:20 【问题描述】:302 FOUND
和 307 TEMPORARY REDIRECT
HTTP 响应之间有什么区别?
The W3 spec 似乎表明它们都用于临时重定向,除非响应特别允许,否则它们都不能被缓存。
【问题讨论】:
【参考方案1】:307 的出现是因为用户代理采用 事实上的 行为来接受接收 302 响应的 POST 请求并将 GET 请求发送到 Location 响应标头。
这是不正确的行为——只有一个 303 应该导致一个 POST 变成一个 GET。如果原始 POST 请求返回 302,用户代理应该(但不)在请求新 URL 时坚持使用 POST 方法。
307 被引入以允许服务器向用户代理清楚地表明,在跟随 Location 响应标头时,客户端应该不进行方法更改。
【讨论】:
任何用户代理响应不正确的例子?通常是很少一部分访问者吗? @makerofthings7 所有浏览器都错误地处理302
。铬 30,IE10。它变成了de facto不正确的实现;这无法更改,因为许多网站错误地发出问题 302。实际上 ASP.net MVC 错误地发出 302,取决于浏览器处理不正确的事实。
@IanBoyd 框架这样做的唯一原因是因为303
还与307
在 HTTP 1.1 规范中一起引入,因此允许与 HTTP 1.0 用户代理向后兼容。当然,真正的问题是我们现在还应该处理 HTTP 1.0 用户代理吗?
@ewanm89 似乎是框架可以创建正确命名的响应方法(例如Response.RedirectSeeOther
),如果客户端不是1.1(例如GET /foo.html
,GET /foo.html HTTP/1.0
),则发出旧版302
.
重定向时看起来像 302 = 303。【参考方案2】:
区别在于重定向 POST
、PUT
和 DELETE
请求以及服务器对用户代理行为的期望 (RFC 2616
):
注意:RFC 1945 和 RFC 2068 指定不允许客户端 更改重定向的方法 要求。但是,大多数现有用户 代理实现将 302 视为 这是一个 303 响应,执行 获取位置字段值 无论最初的请求如何 方法。状态码 303 和 307 已为希望的服务器添加 明确说明是哪一种 的反应是预期的 客户。
另外,请阅读30x redirection codes 上的***文章。
【讨论】:
那么,从解析器/代理/浏览器的角度来看,我们可以简单地将 302 和 307 视为相同,对吧? (exact同一段代码可用于处理这两种情况而无需进一步区分?) 否 - 您可以将 302 和 303 视为相同,但 307 不同。 @kkhugs,没办法,需要 1.0 浏览器才能执行 get-302,就像在 1.1 浏览器中完成 get-307 一样。 1.0 的浏览器需要像 get-302 一样做 post-302,除了它必须首先要求用户确认才能继续,并且方法必须是 post。 执行 get-302 需要 1.1 浏览器,其方式与 get-307 相同。【参考方案3】:307 Internal Redirect
的一个很好的例子是当谷歌浏览器遇到一个对它知道需要严格传输安全的域的 HTTP 调用。
浏览器无缝重定向,使用与原始调用相同的方法。
【讨论】:
你知道谷歌什么时候实现了这个功能吗? 是的,这就是我看到它发生的地方 - 我们的服务器没有发送它 - 在 chrome devtools 中看起来是这样,但它只是 chrome 进行重定向,因为我们有一个严格的传输安全标头跨度> 【参考方案4】: 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 会更好地获得一致的结果。
303:临时重定向,将方法更改为 GET。示例用法:如果浏览器发送 POST 到 /register.php
,则现在加载 (GET) /success.html
.
307:临时重定向,以相同的方式重复请求。示例用法:如果浏览器向/register.php
发送 POST,那么这会告诉它在以下位置重做 POST /signup.php
。
308:永久重定向,以相同方式重复请求。其中 307 是 303 的“无方法更改”对应物,此 308 状态是 301 的“无方法更改”对应物。
RFC 7231 (from 2014) 可读性很强,而且不会过于冗长。如果你想知道确切的答案,推荐阅读。其他一些答案使用 1999 年的 RFC 2616,但没有任何改变。
RFC 7238 指定 308 状态。它被认为是实验性的,但在 2016 年已经是 supported by all major browsers。
【讨论】:
302 未被弃用。 @JulianReschke ***说“302 已被 303 和 307 取代。”也许那是因为我不是母语人士,但对我来说(在这种情况下)被取代和弃用意味着相同:使用 303 或 307,而不是 302。我读错了吗? 错误的是假设***对此有发言权。如果 302 被弃用,HTTP 会这样说。 @JulianReschke 够公平的,我找到了源头,知道了吗?你完全正确。 The RFC其实很好理解,在某些情况下他们甚至推荐302。上面提到的“更新者”和“废弃者”RFC 都不是关于状态码的,所以我猜这个 1999 年的文档确实是我们拥有的最新文档。我会更新我的答案。 相关的是 IANA 状态代码注册表,因此在本例中为 RFC 7231。【参考方案5】:原来只有302
Response | What browsers should do |
---|---|
302 Found |
Redo request with new url |
这个想法是:
如果您在某个位置执行GET
,您可以将您的GET
重做到新网址
如果您在某个位置执行POST
,您可以将您的POST
重做到新网址
如果您在某个位置执行PUT
,您可以将您的PUT
重做到新网址
如果您在某个位置执行DELETE
,您可以将您的DELETE
重做为新网址
等
不幸的是,每个浏览器都做错了。当获得302
时,他们总是会在新 URL 处切换到 GET
,而不是使用 same 动词重试请求(eg、POST
) :
它变成了事实上的错误。
所有浏览器都得到302
错误。所以303
和307
被创建了。
Response | What browsers should do | What browsers actually do |
---|---|---|
302 Found |
Redo request with new url | GET with new url |
303 See Other |
GET with new url | GET with new url |
307 Temporary Redirect |
Redo request with new url | Redo request with new 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) ║
╚═══════════╩════════════════════════╧═══════════════════════╝
或者:
Response | Switch to get? | Temporary? |
---|---|---|
301 Moved Permanently |
No | No |
302 Found |
||
302 Found (actual)
|
Yes | Yes |
303 See Other |
Yes | Yes |
307 Temporary Redirect |
No | Yes |
308 Permanent Redirect |
No | No |
【讨论】:
【参考方案6】:预计 302:重定向在 NEW_URL 上使用相同的请求方法 POST
CLIENT POST OLD_URL -> SERVER 302 NEW_URL -> CLIENT POST NEW_URL
302、303 的实际情况:将更改请求方法从 POST 重定向到 NEW_URL 上的 GET
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 的实际情况:重定向在 NEW_URL 上使用相同的请求方法 POST
CLIENT POST OLD_URL -> SERVER 307 NEW_URL -> CLIENT POST NEW_URL
【讨论】:
【参考方案7】:302 是临时重定向,由服务器生成,而 307 是浏览器生成的内部重定向响应。内部重定向意味着重定向是由浏览器在内部自动完成的,基本上浏览器在发出请求之前将在获取请求中输入的 url 从 http 更改为 https,因此永远不会向 Internet 发出不安全连接的请求。浏览器是否将 url 更改为 https 取决于浏览器预装的 hsts 预加载列表。您还可以通过在您自己的浏览器的 hsts 预加载列表中输入域来将任何支持 https 的站点添加到列表中,该列表位于 chrome://net-internals/#hsts。网站域的所有者可以添加更多的东西通过填写https://hstspreload.org/ 的表格来预加载列表,以便为每个用户预装在浏览器中,即使我提到你也可以特别为自己做。
让我用一个例子来解释: 我向http://www.pentesteracademy.com 发出了一个获取请求,它仅支持 https 并且我的浏览器上的 hsts 预加载列表中没有该域,因为站点所有者尚未注册它以附带预安装的 hsts 预加载列表。 对站点不安全版本的 GET 请求被重定向到安全版本(请参阅上图中响应的名为 location 的 http 标头)。 现在,我通过在 chrome://net-internals/#hsts 添加 hsts 域表单中添加其域来将站点添加到我自己的浏览器预加载列表中,这会修改我的 chrome 浏览器上的个人预加载列表。请务必选择包含子域那里有 STS 选项。 将同一个网站添加到 hsts 预加载列表后,让我们看看它的请求和响应。 您可以在响应标头中看到内部重定向 307,实际上此响应是由您的浏览器生成的,而不是由服务器生成的。 此外,HSTS 预加载列表可以帮助防止用户访问不安全版本的站点,因为 302 重定向很容易受到中间人攻击。 希望我对您了解更多有关重定向有所帮助。
【讨论】:
307:由浏览器在内部使用 HSTS 预加载列表完成,这正是我想听到的。感谢您的确认!【参考方案8】:另外,对于服务器管理员,请务必注意,如果您使用 307 重定向,浏览器可能会向用户显示提示。
例如*,Firefox 和 Opera 会询问用户是否允许重定向,而 Chrome、IE 和 Safari 会透明地进行重定向。
*per Bulletproof SSL and TLS(第 192 页)。
【讨论】:
这仅适用于不安全的请求,例如 POST。【参考方案9】:在某些用例中,攻击者可能会滥用 307 重定向来了解受害者的凭据。
更多信息可以在A Comprehensive Formal Security Analysis of OAuth 2.0的第3.1节中找到。
上述论文的作者提出以下建议:
修复。 与 OAuth 标准中的当前措辞相反,重定向的确切方法不是实现细节,而是对 OAuth 的安全性至关重要。在 HTTP 标准 (RFC 7231) 中,仅明确定义了 303 重定向以删除 HTTP POST 请求的正文。所有其他 HTTP 重定向状态代码,包括最常用的 302,都让浏览器可以选择保留 POST 请求和表单数据。在实践中,浏览器通常会重写 GET 请求,从而丢弃表单数据,但 307 重定向除外。因此,OAuth 标准应该要求上述步骤的 303 重定向才能解决此问题。
【讨论】:
以上是关于302 和 307 重定向有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章
http 301 302 303 307 308 傻傻分不清