找回密码
 加入怎通
查看: 221|回复: 6

彻底搞懂 HTTP 3XX 重定向状态码和浏览器重定向(彻底搞懂楼梯工程量计算)

[复制链接]
我来看看 发表于 2023-03-14 03:30:19 | 显示全部楼层 |阅读模式
2 @1 G! z+ W5 _! p$ A7 S! K+ t7 E# W- p

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

G w) A. T/ B7 `& F

这些状态码大致可以分为三类,其中包括:永久重定向:301,308临时重定向:302,303, 307其他重定向:304这篇文章主要分析永久重定向和临时重定向相关的状态码,至于其他重定向就不在这里细讲了 PS: 正文里提到的 3XX 响应只包含永久重定向和临时重定向所对应的 HTTP 状态码,不包括其他重定向。

" F" {7 ]) [( C

开始我们既需要明白服务器发送的各种重定向状态码是什么含义,还需要搞清楚浏览器收到这些重定向状态码之后会怎么做因此本文会从服务器和浏览器两个部分进行讲解服务器永久重定向永久重定向,是指用户请求的资源地址已经废弃了,现在需要使用新地址来访问,并通过响应 Header 的 Location 字段将这个新的地址告知给用户。

( a" A L; D" m4 {$ e' n7 H3 W

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

+ V) Q* |* E4 W$ J

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

# U2 J4 L+ ^2 \& i, V: f

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

3 t/ r# g8 b0 r" W/ i$ m- q

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

8 S1 u- z! [# Q+ M" D* f2 [% K

应用场景:比如某个应用进行了整站重构,重构之后 URL 发生了改变,这时候可以考虑将老 URL 重定向到新 URL308 Permanent Redirect跟 301 一样,唯一的区别就是浏览器不会改变请求的 HTTP Method 和 Request Body。

2 p* b& W- k! u/ E, Z8 x) U* x! |: M

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

% G0 R% }5 _0 d2 w; R! R% @6 {

可以看出,使用 308 之后,请求的 Method 和 Request Body 都没有发生改变,还是跟原来一样临时重定向由于某些原因,导致用户请求的资源地址临时不可用,但其他某个地址是可访问的,于是就通过响应 Header 的 Location 字段将这个临时地址告知给用户。

# `6 B+ z5 n& L& L% x% _2 J

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

8 _3 s8 N5 S, l6 g; _/ `

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

. S& y, Y, C3 W6 X; C4 g. ^9 j

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

. V7 [. Z) y" G" J: o, B/ D

对于这个场景,302/303 就非常有用了比如,前端可以使用一个固定的 URL 来访问图片资源 (/ H, H- ~. P5 S* u

" h* F0 Q0 v5 |% g

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

8 b' {( f- _. P0 w: n( C" a3 u

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

, U& r" H/ G- i

>这里就会出现一个问题,假设我们页面的 URL 是 http://example.com ,我们只能通过 GET 方法请求这个页面。

& Q9 M* Z7 L& g7 C3 g" X+ P9 @. t

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

8 U/ b+ Q/ q! l w, l* |- J R8 e# }

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

) B0 ]5 D6 a! H- o2 ~6 `

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

" I4 H# @$ r( \: q

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

2 @7 D3 x+ W; ^! f `

注意,如果使用 302 会导致上传失败,原因是 302 会将 PUT 改为 GET 请求,同时 Request Body 也会丢失其他常见的重定向场景域名别称扩大站点的用户覆盖面比如访问 http://www.。

4 B7 {$ E% [. t6 @1 }- ]) k/ O2 W4 {

google.com 会被重定向到 http://google.com迁移到另一个域名强制使用 HTTPS 协议比如访问 http://baidu.com 会被重定向到 https://baidu.com。

0 \* v+ f+ Y' u1 l' Z# c0 Y

保持链接有效当重构网站时,可能会让资源的 URL 发生改变但我们并不想因此使旧链接失效,因为这些链接不仅可以给你带来宝贵的用户,还能够帮助优化 SEO,因此需要建立从旧链接到新链接的重定向映射浏览器我们已经了解了各种关于重定向的 HTTP 状态码,那么浏览器收到这些状态码之后会做些什么呢?当浏览器收到 3XX 响应之后,是否会将地址栏的 URL 修改为响应 Header 中 Location 字段所指定的 URL,并跳转到这个新的 URL 呢? 请接着往下看。

& z6 G* F9 Q# ^2 `3 G. G

收到 3XX 响应后,浏览器是否会改变地址栏并跳转?浏览器是否会改变地址栏并跳转, 其实取决于请求的 URL 是否会让文档加载/重新加载这里所指的文档加载/重新加载,既包括当我们通过浏览器地址栏访问某个 URL、刷新页面所导致的文档加载,也包括我们通过 。

5 y6 t' j0 K4 L. D, T

window.location 让文档用新的 URL 加载只有在这些情况下,如果我们请求的 URL 返回了 3XX 响应,浏览器才会读取响应 Header 里面的 Location 字段,并将浏览器的地址栏修改为这个字段所指定的 URL,然后跳转到这个 URL。

( s8 e/ ~, ^; {, Y3 m. Y% k& I% I

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

4 [4 u. ]/ |4 v

PS: React Router 这样的路由跳转,不会让文档重新加载 ( 因为使用的是 History API )但是,如果是通过 fetch/XMLHttpRequest 调用所获取到的 3XX 响应,浏览器是不会改变当前地址栏的 URL 并跳转的。

8 L0 {5 Y0 q4 W

试想,我们在访问图片时,经常会得到很多 302 响应,如果浏览器要跳转 URL,岂不是会导致整个浏览器崩溃window.location + 3XX 响应window.location 能够让文档用新的 URL 加载,默认会将新的 URL push 到浏览器 history 的路由堆栈里面,如果你想使用 replace 的方式,可以调用 window.location.replace() 方法:

+ x) X! l$ h1 F9 R

window.location="http://www.mozilla.org";functionreloadPageWithHash(){varinitialPage=window.location.

; O( E" u& B" b. F5 P2 E. y

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

, q, p3 u: A: Y. Z' S1 U% y! w

通过 window.location 再配合 302 响应,我们可以快速将用户导向三方授权点,不需要加载任何 JS,非常快速方便参考:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Redirections。

7 b3 M: \" e/ Z8 D) `3 F8 a 9 N( N! I* x! @! P + `# m8 r& f$ S9 Z) _1 f( \2 m2 r7 ?/ A! ~2 E; Q( @6 C* { ; a H& l/ q+ |2 O

暂时无法加载帖子列表

回复

使用道具 举报

.。。小结巴 发表于 2026-03-14 15:09:11 | 显示全部楼层
这个思路很新颖,打开了新世界的大门,谢谢分享
回复

使用道具 举报

XYDUANZAO 发表于 2026-07-25 01:00:33 | 显示全部楼层
完全赞同,我也是这么认为的,英雄所见略同~
回复

使用道具 举报

liming23 发表于 2026-07-31 20:36:40 | 显示全部楼层
楼主辛苦了,整理这么多内容,必须点赞收藏
回复

使用道具 举报

huyi1009 发表于 2026-08-03 23:54:45 | 显示全部楼层
这个分享太实用了,刚好能用到,感谢楼主!
回复

使用道具 举报

我的未来不是梦 发表于 2026-09-30 22:20:12 | 显示全部楼层
楼主太厉害了,整理得这么详细,必须支持
回复

使用道具 举报

guanjiesj 发表于 2026-09-30 23:41:10 | 显示全部楼层
内容很干货,没有多余的废话,值得反复看
回复

使用道具 举报

    您需要登录后才可以回帖 登录 | 加入怎通

    本版积分规则

    QQ|手机版|小黑屋|网站地图|真牛社区 ( 苏ICP备2023040716号-2 )

    GMT+8, 2026-10-1 14:06 , Processed in 0.036664 second(s), 25 queries , Gzip On.

    免责声明:本站信息来自互联网,本站不对其内容真实性负责,如有侵权等情况请联系420897364#qq.com(把#换成@)删除。

    Powered by Discuz! X3.5

    快速回复 返回顶部 返回列表