彻底搞懂 HTTP 3XX 重定向状态码和浏览器重定向

最近好好研究了一下 HTTP 的 3XX 状态码,发现这里面涉及到的知识点还挺多的,很多在我们日常开发过程中也会用到,于是就想通过这篇文章来和大家聊一聊它们的含义以及应用场景。

3XX 状态码是关于重定向的,常见的状态码有:301,302,303,304,307 和 308。这些状态码大致可以分为三类,其中包括:

  • 永久重定向:301,308
  • 临时重定向:302,303, 307
  • 其他重定向:304

这篇文章主要分析永久重定向和临时重定向相关的状态码,至于其他重定向就不在这里细讲了。

PS: 正文里提到的 3XX 响应只包含永久重定向和临时重定向所对应的 HTTP 状态码,不包括其他重定向。

开始

我们既需要明白服务器发送的各种重定向状态码是什么含义,还需要搞清楚浏览器收到这些重定向状态码之后会怎么做。因此本文会从服务器和浏览器两个部分进行讲解。

服务器

永久重定向

永久重定向,是指用户请求的资源地址已经废弃了,现在需要使用新地址来访问,并通过响应 Header 的 Location 字段将这个新的地址告知给用户。

就好比胡同口有一家我们常去的饭店,但是由于旧城改造这家店搬迁到了另一个地方。有一天我们准备去这家店吃饭,发现门口张贴告示:此店已迁移到 XXX,并附上了详细的新地址。也就是说,之后如果我还想去这家店吃饭,只能去新的地址。

301 Moved Permanently

表示请求资源已经被移动到了由 Location 头部指定的 URI 上,是固定的不会再改变。在用新 URL 发起请求时,对于 GET 请求保持不变,但是对于 POST 请求,尽管标准要求浏览器在收到该响应时不应该修改 HTTP Method 和 Request Body,但是大多数浏览器没有遵守这个标准,会把原本为 POST 的请求重定向到 GET 请求上。

我们拿 Chrome 浏览器测试了一下,结果如下:

从上面的截图中可以看出,浏览器在收到 302 响应之后,从 Location 里面获取到了 /pets 这个新的地址,并发起了新的请求。但是,这个新的请求使用的是 GET 方法而非我们原来的 POST 方法,Request Body 也丢失了。

应用场景:

比如某个应用进行了整站重构,重构之后 URL 发生了改变,这时候可以考虑将老 URL 重定向到新 URL。

308 Permanent Redirect

跟 301 一样,唯一的区别就是浏览器不会改变请求的 HTTP Method 和 Request Body。

我们又继续拿 Chrome 测试了一下,结果如下:

可以看出,使用 308 之后,请求的 Method 和 Request Body 都没有发生改变,还是跟原来一样。

临时重定向

由于某些原因,导致用户请求的资源地址临时不可用,但其他某个地址是可访问的,于是就通过响应 Header 的 Location 字段将这个临时地址告知给用户。

就好比我们去一家饭店吃饭,到门口发现老板张贴告示:家里临时有事,请去附近另一个分店用餐,并附上了分店的详细地址。这样,我们就可以先临时去这家分店用餐,等之后老板回来了,我们又可以在原来这家店继续用餐。

302 Found

在收到 302 响应之后,浏览器会发起新的请求,尽管标准要求浏览器在收到该响应时不应该修改 HTTP Method 和 Request Body,但是大多数浏览器都没有遵守这个标准。大多数浏览器会将 302 请求视为 303 请求,也就是说 302 和 303 几乎是一样的。

应用场景举例:

通常图片资源会放到类似 S3 这样的静态资源服务器,出于对隐私和安全的考虑,我们有时不能直接通过静态资源服务器的 URL 访问到这个图片,而是需要后端通过身份凭证去 S3 签发一个临时地址(这个地址用一次就失效了,下一次需要重新签发),然后我们才能通过这个临时地址访问到真正的图片资源。

对于这个场景,302/303 就非常有用了。比如,前端可以使用一个固定的 URL 来访问图片资源 (<img src="/image/foo.jpg"),这个 URL 由后端提供,后端在生成完临时地址之后,可以直接通过 302/303 重定向到这个新的地址,接下来浏览器会再次发起请求,获取新地址指向的这个图片资源。

303 See Other

浏览器在收到 303 响应之后,除 GET 方法保持不变之外,其他所有方法都会被改为 GET 方法,同时 Request Body 也会丢失。一般用于将 POST 方法重定向到 GET 方法。

应用场景举例:

假设我们有一个非常原始的表单,这个表单是通过在 HTML 上设置 action 和 method 来提交的。在表单提交之后,浏览器会自动跳转到 action 所在的地址,并使用 method 所指定的方法向服务器发起请求,在收到服务器的303 响应之后,又需要跳转回原来这个页面。

<form action="http://example.com/api/form" method="POST">
    <input type="text" name="name" placeholder="name">
    <input type="email" name="email" placeholder="email">
    <input type="submit" value="Submit">
</form>

这里就会出现一个问题,假设我们页面的 URL 是 http://example.com ,我们只能通过 GET 方法请求这个页面。而提交表单所使用的 URL 是 http://example.com/api/form ,我们只能通过 POST 方法来调用这个接口。在使用 POST 方法提交表单之后,如果我们想返回原来的页面,只能使用 GET 方法发起请求,因此我们需要使用 303 状态码,将原来的 POST 方法改成 GET。

307 Temporary Redirect

307 和 303 一样,唯一的区别就是浏览器不会改变请求的 HTTP Method 和 Request Body。对于 POST/PUT 等非 GET 请求很有用。

应用场景:

在上传文件时,我们通常会调用后端提供的某个 API (/upload),但由于上传会占用大量的服务器资源和带宽,这个 API 一般不会处理真正的上传,而是通过另一个专门的上传服务来完成。这意味着我们需要调用两次 API 才能完成上传功能,一次是调用后端接口获取真正的上传地址,另一次是携带 Request Body 请求这个上传地址,完成真正的上传。

如果让两个 API 的请求参数和方法保持一致,那么对于前端来说,只需要发起一次请求即可,后端在生成完上传地址后,通过 307 重定向到这个地址,然后浏览器会使用之前的 Request Body 和 HTTP Method 请求这个新的地址,这样就完成了上传。

注意,如果使用 302 会导致上传失败,原因是 302 会将 PUT 改为 GET 请求,同时 Request Body 也会丢失。

其他常见的重定向场景

域名别称

  1. 扩大站点的用户覆盖面。比如访问 http://www.google.com 会被重定向到 http://google.com
  2. 迁移到另一个域名。
  3. 强制使用 HTTPS 协议。比如访问 http://baidu.com 会被重定向到 https://baidu.com

保持链接有效

当重构网站时,可能会让资源的 URL 发生改变。但我们并不想因此使旧链接失效,因为这些链接不仅可以给你带来宝贵的用户,还能够帮助优化 SEO,因此需要建立从旧链接到新链接的重定向映射。

浏览器

我们已经了解了各种关于重定向的 HTTP 状态码,那么浏览器收到这些状态码之后会做些什么呢?当浏览器收到 3XX 响应之后,是否会将地址栏的 URL 修改为响应 Header 中 Location 字段所指定的 URL,并跳转到这个新的 URL 呢? 请接着往下看。

收到 3XX 响应后,浏览器是否会改变地址栏并跳转?

浏览器是否会改变地址栏并跳转, 其实取决于请求的 URL 是否会让文档加载/重新加载。这里所指的文档加载/重新加载,既包括当我们通过浏览器地址栏访问某个 URL、刷新页面所导致的文档加载,也包括我们通过 window.location 让文档用新的 URL 加载。只有在这些情况下,如果我们请求的 URL 返回了 3XX 响应,浏览器才会读取响应 Header 里面的 Location 字段,并将浏览器的地址栏修改为这个字段所指定的 URL,然后跳转到这个 URL。

一般来说文档加载/重新加载都会产生一个 Document 类型的请求,如下所示:

PS: React Router 这样的路由跳转,不会让文档重新加载 ( 因为使用的是 History API )

但是,如果是通过 fetch/XMLHttpRequest 调用所获取到的 3XX 响应,浏览器是不会改变当前地址栏的 URL 并跳转的。试想,我们在访问图片时,经常会得到很多 302 响应,如果浏览器要跳转 URL,岂不是会导致整个浏览器崩溃。

window.location + 3XX 响应

window.location 能够让文档用新的 URL 加载,默认会将新的 URL push 到浏览器 history 的路由堆栈里面,如果你想使用 replace 的方式,可以调用 window.location.replace() 方法:

window.location = "http://www.mozilla.org";

function reloadPageWithHash() {
  var initialPage = window.location.pathname;
  window.location.replace('http://example.com/#' + initialPage);
}

应用场景:

在使用 OAuth2 鉴权时(比如微信登录),可以通过 window.location 重定向到自己服务器的授权地址(支持多个平台登录时,可以由后端统一处理),然后服务器会生成一个三方授权点的地址,并通过 302 响应告知给浏览器,浏览器在收到响应之后会跳转到这个三方授权点的 URL(微信登录页),完成授权之后,三方授权页面会通过 window.location 再重定向回我们自己的页面。

通过 window.location 再配合 302 响应,我们可以快速将用户导向三方授权点,不需要加载任何 JS,非常快速方便。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Http状态码指的是Hypertext Transfer Protocol (HTTP)协议的通信状态代,用于指示浏览器和服务器之间的通信是否成功。它们用于指示服务器如何处理用户的请求,以及浏览器应如何显示给用户。常见的Http状态码包括200 OK(请求成功)、404 Not Found(未找到)、403 Forbidden(禁止访问)、500 Internal Server Error(服务器内部错误)等等。 ### 回答2: HTTP状态码是指在进行HTTP协议通信过程中,服务器向客户端返回的一个三位数的数字。这个数字用来表示服务器对请求的处理结果,从而告知客户端当前请求的状态。 HTTP状态码分为5个类别,分别以不同的数字开头: 1xx:信息类状态码,表示接收的请求已被成功接收,需要继续处理。 2xx:成功类状态码,表示请求已被成功接收、理解和处理。 3xx重定向状态码,服务器需要进一步操作以完成请求。 4xx:客户端错误类状态码,表示客户端发送的请求有误或不可被服务器所理解。 5xx:服务器错误类状态码,表示服务器在处理请求时发生了错误。 常见的HTTP状态码有: 200 OK:表示请求成功,服务器成功处理并返回了请求的资源。 301 Moved Permanently:表示请求的资源被永久重定向到其他地址。 400 Bad Request:表示客户端发送的请求有错误,服务器无法理解。 404 Not Found:表示请求的资源不存在。 500 Internal Server Error:表示服务器在处理请求时发生了未知的错误。 HTTP状态码是在进行网页浏览、文件下载、网站交互等一系列HTTP通信中非常重要的一个组成部分。通过状态码,客户端能够了解到请求的结果,根据不同的状态码采取不同的处理方式,从而达到更好的用户体验和系统交互效果。 ### 回答3: HTTP状态码是用来表示客户端请求与服务器响应之间的状态的标准化代。每个HTTP响应状态码都由一个三位数字组成,每个数字有特定的含义。以下是常见的HTTP状态码及其解释: 200 OK:表示请求成功,服务器成功处理了请求,并返回了请求的资源。 301 Moved Permanently:请求的资源已经被永久移动到新的位置,客户端需要更新请求的URL。 400 Bad Request:请求错误,服务器无法理解客户端发送的请求。 401 Unauthorized:请求要求身份验证,客户端没有提供有效的身份验证凭据。 403 Forbidden:服务器拒绝该请求,客户端没有访问权限。 404 Not Found:请求的资源不存在,服务器无法找到请求的URL。 500 Internal Server Error:服务器遇到了内部错误,无法完成请求。 除了上述状态码外,还有许多其他状态码,如302 Found(临时移动)、503 Service Unavailable(服务不可用),每个状态码都有其特定的含义,用于指示请求的结果和错误的原因,以便客户端和服务器能够进行相应的处理和调试。服务器返回的状态码对于开发者来说是非常重要的,可以帮助我们了解请求的结果和问题所在,对于调试和错误处理非常有帮助。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值