一、为什么302和307的区别能让表单数据消失?
做Nginx重定向的时候,很多人觉得302和307都是"临时重定向",随便用哪个都行。但当你的请求是POST方法的时候,这一个选择就能让用户的表单数据直接消失。
核心区别就一句话:302允许浏览器把POST变成GET,307不允许。
这意味着什么?当用户提交了一个表单,你的服务器返回302重定向,浏览器可能把POST请求变成GET请求去访问新地址——请求体(body)里的数据全没了。而307会要求浏览器用原来的POST方法去请求新地址,表单数据完整保留。
二、HTTP规范怎么说?
2.1 RFC 1945:302的"历史遗留问题"
302状态码最早定义在HTTP/1.0规范(RFC 1945)中。当时规范说的是:"收到302后,客户端应该用GET方法发起对新地址的请求",即使原始请求是POST。
这就导致了一个广泛存在的问题:浏览器在302重定向时,默认把POST改成了GET。这个行为在HTTP/1.0时代就定下来了,后来为了兼容性,主流浏览器一直保持这个行为。
2.2 RFC 7231:307的"纠错补丁"
HTTP/1.1规范(RFC 7231)意识到了302的这个问题,专门引入了307状态码来"纠错":
- 307 Temporary Redirect:要求客户端不能改变请求方法,POST还是POST,GET还是GET
- 请求体(body)必须保持原样转发到新地址
简单说,307就是"老老实实按原来的方法请求新地址",而302是"浏览器可以自作主张改成GET"。
2.3 对比速查表
| 特性 | 302 Found | 307 Temporary Redirect |
|---|---|---|
| 规范版本 | HTTP/1.0 (RFC 1945) | HTTP/1.1 (RFC 7231) |
| POST请求处理 | 浏览器可能改为GET | 必须保持POST |
| 请求体(body) | 可能被丢弃 | 完整保留 |
| 查询参数 | 保留 | 保留 |
| 缓存行为 | 不缓存 | 不缓存 |
| 浏览器兼容 | 所有浏览器 | 所有现代浏览器 |
| 典型用途 | 临时跳转到其他页面 | 临时跳转且需保留POST |
三、浏览器行为实测
3.1 场景:POST表单提交后302重定向
假设用户在登录页面提交表单:
POST /login HTTP/1.1
Content-Type: application/x-www-form-urlencoded
username=admin&password=123456
服务器返回302重定向到/dashboard:
HTTP/1.1 302 Found
Location: /dashboard
浏览器的实际行为:
GET /dashboard HTTP/1.1
// 注意:POST变成了GET,body消失了!
这就是问题所在——POST变GET,请求体没了。如果/dashboard接口只接受POST请求,还会返回405 Method Not Allowed。
3.2 场景:POST表单提交后307重定向
同样的请求,服务器返回307:
HTTP/1.1 307 Temporary Redirect
Location: /dashboard
浏览器的实际行为:
POST /dashboard HTTP/1.1
Content-Type: application/x-www-form-urlencoded
username=admin&password=123456
POST方法和请求体完整保留,数据一个字节都没丢。
3.3 主流浏览器行为汇总
- Chrome/Edge:302下POST→GET,307下POST→POST
- Firefox:302下POST→GET,307下POST→POST
- Safari:302下POST→GET,307下POST→POST
- curl:302下默认不跟随重定向(-L时POST→GET),307下保持POST
所有主流浏览器对302的行为一致:POST变GET。307则统一保留原始方法。
四、Nginx配置对比
4.1 Nginx return 302 配置
server {
listen 80;
server_name example.com;
# 302临时重定向
location /old-api {
return 302 https://example.com/new-api;
}
}
问题:如果客户端用POST请求/old-api,302会让浏览器用GET访问/new-api,POST数据丢失。
4.2 Nginx return 307 配置
server {
listen 80;
server_name example.com;
# 307临时重定向(保留POST方法)
location /old-api {
return 307 https://example.com/new-api;
}
}
客户端用POST请求/old-api时,307会让浏览器继续用POST访问/new-api,请求体完整保留。
4.3 带查询参数的重定向
302和307对查询参数的处理是一样的——都保留:
# 302带参数
return 302 https://example.com/new-api;
# 307带参数
return 307 https://example.com/new-api;
查询参数在两种状态下都不丢失,区别只在于请求方法和请求体。
4.4 rewrite与return的配合
# rewrite + 302
rewrite ^/old-api(.*)$ https://example.com/new-api redirect;
# rewrite + 307(需要return配合)
location /old-api {
return 307 https://example.com/new-api;
}
注意:Nginx的rewrite指令的redirect标志产生302,permanent标志产生301。要产生307,只能用return 307。
五、5个实战场景选择建议
场景1:API接口迁移(POST请求)
选307,别犹豫。
旧接口/api/v1/user收到POST请求,需要临时跳转到/api/v2/user。307保证POST方法和JSON body完整传递,302会把POST变GET,API直接报错。
场景2:表单提交后跳转
看跳转目标是否需要POST数据。
如果表单提交后只是跳到一个"提交成功"页面(不需要表单数据),302就够了。如果跳转目标还需要处理表单数据,必须用307。
场景3:HTTP跳HTTPS(GET请求)
302和307效果一样,302更常见。
纯GET请求的HTTP→HTTPS跳转,302和307行为一致(GET不会变),302更广泛被支持,搜索引擎也更理解302的含义。
场景4:AB测试临时分流
用302。
AB测试的分流跳转通常是GET请求,302语义明确"这是临时跳转",搜索引擎不会把权重转移到新URL。307也能用但语义稍不同。
场景5:文件上传接口重定向
必须307。
文件上传是POST+multipart body,302会把POST变GET,上传的文件数据直接丢失。307保留POST方法和完整的文件body。
六、curl验证命令
用curl可以直观验证302和307的行为差异:
6.1 验证302行为
# -L跟随重定向,-X POST指定方法
curl -v -L -X POST -d "user=admin&pass=123" http://example.com/old-api
# 输出中会看到:
# > POST /old-api
# < HTTP/1.1 302 Found
# > GET /new-api (POST变成了GET!)
6.2 验证307行为
curl -v -L -X POST -d "user=admin&pass=123" http://example.com/old-api
# 输出中会看到:
# > POST /old-api
# < HTTP/1.1 307 Temporary Redirect
# > POST /new-api (POST方法保留了!)
6.3 只看重定向状态码
# 不跟随重定向,只看返回码
curl -o /dev/null -s -w "%{http_code}" -X POST http://example.com/old-api
七、308永久重定向补充
与307对应的"永久版本"是308(Permanent Redirect)。
- 301 vs 308:301允许POST变GET,308不允许
- 302 vs 307:302允许POST变GET,307不允许
所以完整的选择逻辑是:
| 需求 | 临时 | 永久 |
|---|---|---|
| 允许POST变GET | 302 | 301 |
| 保留原始方法 | 307 | 308 |
在Nginx中配置308:
return 308 https://example.com/new-api;
八、总结
302和307的选择不是"随便都行",而是取决于你的请求方法:
- GET请求:302和307效果一样,302更主流
- POST请求:必须用307,302会让表单数据消失
- 文件上传、API迁移、需要保留body的场景:307是唯一选择
- 308是307的永久版,301是302的永久版,同理
记住这个口诀:POST重定向用307,GET随便302。选错状态码,数据就没了。
相关文章
版权声明
本文仅代表个人观点。
本文系AI辅助作者原创,未经许可,转载请保留原文链接。

发表评论