← 路由设计 · 稳定入口与可变目标 / HTTP 重定向 · 301/302/303/307/308 到底差在哪 待审核 4 / 23

HTTP 重定向 · 301/302/303/307/308 到底差在哪

路由匹配到一条请求后,handler 不一定要返回内容——它也可以回一个 3xx 状态码 + 一个 Location 响应头,意思是「你要的东西不在这里,去那边」。客户端读到后会自动再发一次请求Location。这就是重定向:服务端只改 Location,就能把同一个入口指向任意新目标。

五个重定向码看着像近义词,其实只差两个正交维度永久还是临时(决定能不能被浏览器缓存)、跳过去时方法保不保持POST 保持 POST,还是被悄悄改成 GET)。

两维度速记。 永久(301 / 308):「这个地址已停用,以后都走新的」——浏览器会缓存这条跳转,下次直接去新址、连旧址都不请求了(配错很难收回)。临时(302 / 303 / 307):「暂时去那边,旧址还作数」——默认不缓存。方法保持(307 / 308):POST 原样带着 body 跟过去。方法可能被改(301 / 302):历史上浏览器把非 GET 偷偷改成 GET——行为不确定,这正是 307/308 被发明出来的理由。强制改 GET(303):无论原方法,一律改 GET

状态码 永久? 方法 典型用途
301 Moved Permanently 永久 · 可缓存 可能被改 GET 永久搬家:旧 URL 不再用,把 SEO 权重 / 书签迁到新址
302 Found 临时 可能被改 GET 临时跳转:最常用也最常被误用(其实多数场景想要的是 307 或 303)
303 See Other 临时 强制改 GET POST 之后跳到一个 GET 结果页——经典 PRG(Post/Redirect/Get)防重复提交
307 Temporary Redirect 临时 原样保持 临时跳转,且严格保持方法与 body(POST 仍是 POST)
308 Permanent Redirect 永久 · 可缓存 原样保持 永久跳转,且严格保持方法与 body——API 端点搬迁 / 版本切换的首选

想「临时跳又别改方法」用 307;想「永久跳又别改方法」用 308;POST 提交后跳到结果页防重复提交用 303(PRG)。

1 · 把它当「可配置的跳转链接」· 版本切换

回到一个真实需求:对外只暴露一个稳定端点 /api/users,但后端实现在不断升级 v1v2v3v1 \to v2 \to v3。做法是让 /api/users 回一个 308,Location 指向当前版本。需求一变,服务端改一行 Location 配置即可把所有调用方导到新版本,而调用方代码里那个 /api/users 不用改

为什么偏偏是 308 而不是 301?因为 API 调用常是 POST / PUT:308 严格保持方法与 bodyPOST /api/users 会原样变成 POST /api/v2/users;若用 301,POST 可能被浏览器 / 某些 client 改成 GET,请求体丢失、语义全错。上面把状态码切到 308、方法切到 POST、点版本预设,观察方法保持不变地跟到新版本。

重定向不是免费的。 每一跳都是一次完整的往返(RTT)。链路越长越慢,还可能绕成循环ABAA\to B\to A),所以客户端会限制最大跳数(浏览器约 20 跳后报错)。能在服务端内部 rewrite(内部转发) 解决的,就别让客户端多跑一趟外部 redirect。另外:301/308 一旦被缓存就很难纠正,上线前务必想清楚「这真的是永久吗」。

2 · 相关页

</content>