HTTP 重定向踩坑实录:307、301、308 问题快速排查指南
🎯 前言
作为前端开发,你可能遇到过这些诡异问题:
- "POST 请求数据莫名消失,后端说根本没收到"
- "本地开发突然全部跳转 HTTPS,localhost 都访问不了"
- "生产环境加载巨慢,Network 里全是红色的重定向"
- "新上线的测试域名所有浏览器都打不开,显示连接被拒绝"
本文通过真实踩坑案例,教你快速定位和解决重定向问题。
💥 案例一:POST 请求数据神秘消失
💀 问题症状
javascript
// 前端代码
fetch('http://api.example.com/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
username: 'admin',
password: '123456'
})
})
.then(res => res.json())
.then(data => console.log(data))
现象:
- ❌ 接口返回
400 Bad Request: Missing credentials - ❌ 后端日志显示收到的是 GET 请求,body 为空
- ❌ 前端明明发的是 POST,怎么就变成 GET 了?
- ❌ 本地测试正常,部署到生产就出问题
用户影响:
- 所有登录、注册、提交表单操作全部失败
- 用户反馈"一直提示参数错误"
- 错误率突然飙升到 100%
🔍 快速定位
1. 打开 Chrome DevTools → Network
yaml
Name: login
Status: 301 Moved Permanently ← 第一个请求
Request Method: POST
Name: login
Status: 400 Bad Request ← 第二个请求
Request Method: GET ← 变了!
2. 点击第一个请求查看 Response Headers
http
HTTP/1.1 301 Moved Permanently
Location: https://api.example.com/login
3. 确认问题:301 重定向导致 POST 变 GET
⚡ 解决方案
去哪看:
- 检查 Nginx/Apache 配置文件中的
return 301或redirect 301 - 找运维确认 HTTP → HTTPS 重定向配置
去哪改:
nginx
# ❌ 错误配置(导致 POST 变 GET)
server {
listen 80;
return 301 https://$server_name$request_uri;
}
# ✅ 正确配置(保持 POST)
server {
listen 80;
return 307 https://$server_name$request_uri; # 改这里
}
或者前端直接改用 HTTPS:
javascript
fetch('https://api.example.com/login', { // 加 s
method: 'POST',
// ...
})
💥 案例二:本地开发突然无法访问
💀 问题症状
javascript
// 本地启动项目
npm run dev
// ✅ Server running at http://localhost:8080
访问 http://localhost:8080 时:
现象:
- ❌ 浏览器自动跳转到
https://localhost:8080 - ❌ 页面显示"无法访问此网站" 或 "连接被拒绝"
- ❌ Network 面板显示
307 Internal Redirect - ❌ 状态栏显示
Non-Authoritative-Reason: HSTS - ❌ 昨天还能访问,今天突然就不行了
- ❌ 同事的电脑能正常访问,只有你的电脑有问题
关键线索:
makefile
Status: 307 Internal Redirect
Non-Authoritative-Reason: HSTS ← 关键!
🔍 快速定位
1. 确认是 HSTS 问题
打开 chrome://net-internals/#hsts,输入 localhost
如图:
操作如下:
arduino
Query HSTS/PKP domai 输入当前域名搜索
// 如果有内容说明是HSTS相关
2. 回忆最近操作
- 是否访问过生产环境
https://example.com? - 生产环境是否设置了
includeSubDomains? - 是否在
localhost上测试过 HTTPS?
⚡ 解决方案
临时方案(1分钟):清除 HSTS
如图:

markdown
1. chrome://net-internals/#hsts
2. Delete domain security policies
3. 输入: localhost
4. 点击 Delete
5. 刷新页面
永久方案(5分钟):本地启用 HTTPS
bash
# 安装 mkcert
brew install mkcert # Mac
choco install mkcert # Windows
# 生成证书
mkcert -install
mkcert localhost 127.0.0.1
javascript
// vite.config.js
import fs from 'fs'
export default {
server: {
https: {
key: fs.readFileSync('./localhost-key.pem'),
cert: fs.readFileSync('./localhost.pem')
}
}
}
快速测试方案(0分钟):
- 用隐身模式
Ctrl+Shift+N - 或换个端口
port: 3000
💥 案例三:网站加载巨慢,重定向循环
💀 问题症状
用户投诉:
- "网站加载要等 10 秒才出来"
- "页面一直在转圈"
Network 面板显示:
app.js - 301 Moved Permanently - 2.3s
app.js - 301 Moved Permanently - 2.1s
app.js - 301 Moved Permanently - 1.8s
app.js - 200 OK - 0.5s
现象:
- ❌ 同一个资源重定向 3-5 次
- ❌ 每次重定向耗时 2 秒左右
- ❌ 最终能加载成功,但体验极差
- ❌ 清除浏览器缓存后第一次访问更慢
关键特征:
- 路径越来越长:
/static/app.js→/assets/static/app.js→/assets/assets/static/app.js - 每次重定向都命中 CDN 缓存(
X-Cache: HIT)
🔍 快速定位
1. 追踪重定向链
bash
curl -L -v https://cdn.example.com/static/app.js 2>&1 | grep -E "HTTP|Location"
# 输出
> GET /static/app.js
< HTTP/2 301
< Location: /assets/static/app.js
> GET /assets/static/app.js
< HTTP/2 301
< Location: /assets/assets/static/app.js ← 路径重复了!
2. 绕过 CDN 测试源站
bash
curl -I https://origin.example.com/static/app.js
# 输出
Location: /assets/static/app.js ← Nginx 配置错误
3. 确认问题:重定向规则路径拼接错误
⚡ 解决方案
去哪看:
- 检查 Nginx 的
location和rewrite规则 - 特别注意
$uri变量的使用
去哪改:
nginx
# ❌ 错误($uri 包含完整路径)
location /static/ {
return 301 /assets/$uri; # /static/app.js → /assets/static/app.js
}
# ✅ 正确(用正则提取文件名)
location ~ ^/static/(.*)$ {
return 301 /assets/$1; # /static/app.js → /assets/app.js
}
改完后立即清除 CDN 缓存:
bash
# Cloudflare
curl -X POST "https://api.cloudflare.com/.../purge_cache" \
--data '{"files":["https://cdn.example.com/static/*"]}'
💥 案例四:新测试域名完全无法访问
💀 问题症状
背景:
- 新上线测试环境
test.example.com - 只配置了 HTTP(80 端口),没配 HTTPS
现象:
- ❌ 所有浏览器都显示"无法访问此网站"
- ❌ curl 能访问成功,但浏览器不行
- ❌ 错误信息:
ERR_SSL_PROTOCOL_ERROR或连接被重置 - ❌ Network 面板显示
(failed) net::ERR_CONNECTION_REFUSED - ❌ 同事新装的浏览器也访问不了(排除缓存问题)
关键线索:
- 主域名
example.com几个月前加入了 HSTS Preload - 当时设置了
includeSubDomains
🔍 快速定位
1. 检查 Preload 状态
访问 https://hstspreload.org/?domain=example.com
json
{
"status": "preloaded",
"includeSubDomains": true ← 问题根源!
}
2. 确认浏览器行为
yaml
chrome://net-internals/#hsts
输入: test.example.com
Static STS domain: yes ← 在浏览器内置列表中
Static upgrade mode: FORCE_HTTPS
Static STS include subdomains: yes
3. 确认问题:Preload 强制所有子域名用 HTTPS
⚡ 解决方案
去哪看:
- 检查主域名是否在 HSTS Preload List
- 确认
Strict-Transport-Security响应头是否有includeSubDomains
只有两个选择:
方案 1:为测试域名配置 HTTPS(推荐,30分钟)
bash
# 申请通配符证书
certbot certonly --dns-cloudflare -d *.example.com
nginx
server {
listen 443 ssl;
server_name test.example.com;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
}
方案 2:换独立域名(推荐,5分钟)
nginx
# 不用 example.com 的子域名
server {
listen 80;
server_name test-env.otherdomain.com; # 完全独立的域名
}
不推荐:从 Preload 移除
- 需要几个月才能生效
- 几乎不可逆
- 影响所有用户
💥 案例五:HTTPS 页面资源加载失败
💀 问题症状
html
<!-- HTTPS 页面 -->
<script src="http://cdn.example.com/jquery.js"></script>
现象:
- ❌ 控制台报错:
Mixed Content: ... blocked - ❌ 页面功能异常(依赖的 JS 没加载)
- ❌ 部分用户能正常访问,部分不行(诡异!)
- ❌ 无痕模式能访问,正常模式不行
关键线索:
rust
Mixed Content: The page at 'https://www.example.com/' was loaded over HTTPS,
but requested an insecure resource 'http://cdn.example.com/jquery.js'.
This request has been blocked.
🔍 快速定位
1. 检查是否是 HSTS 导致的差异
bash
# 测试 CDN 是否有 HSTS
curl -I https://cdn.example.com
Strict-Transport-Security: max-age=31536000 ← 有 HSTS
2. 理解问题原因
- 访问过 CDN 的用户:浏览器自动升级 HTTP → HTTPS(能加载)
- 没访问过的用户:浏览器阻止混合内容(加载失败)
⚡ 解决方案
去哪改:
- 全局搜索代码中的
http:// - 检查 HTML、JS、CSS 中的资源引用
改什么:
html
<!-- ❌ 错误 -->
<script src="http://cdn.example.com/jquery.js"></script>
<!-- ✅ 方案 1:协议相对 URL -->
<script src="//cdn.example.com/jquery.js"></script>
<!-- ✅ 方案 2:明确 HTTPS -->
<script src="https://cdn.example.com/jquery.js"></script>
快速修复:CSP 自动升级
html
<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">
🛠️ 快速排查工具
Chrome DevTools
javascript
// 检查重定向次数
performance.getEntriesByType('navigation')[0].redirectCount
// 检查 HSTS
// 直接访问:chrome://net-internals/#hsts
命令行
bash
# 查看重定向链
curl -sI -L http://example.com | grep -E "HTTP|Location"
# 检查 HSTS 头
curl -I https://example.com | grep -i strict
# 跟随重定向并显示详情
curl -L -v http://example.com 2>&1 | less
在线工具
- Redirect Checker : httpstatus.io/
- HSTS Preload : hstspreload.org/
- SSL Labs : www.ssllabs.com/ssltest/
📋 问题决策树
markdown
遇到重定向问题
↓
是否看到 "307 Internal Redirect"?
├─ 是 → HSTS 问题
│ → chrome://net-internals/#hsts 查看并清除
└─ 否 → 继续
POST 请求是否失败?
├─ 是 → 检查状态码
│ ├─ 301/302 → Nginx 改用 307
│ └─ 其他 → 检查服务器日志
└─ 否 → 继续
是否有多次重定向?
├─ 是 → 检查 Nginx 重写规则
│ → 清除 CDN 缓存
└─ 否 → 继续
子域名无法访问?
└─ 检查主域名 HSTS Preload 状态
→ 为子域名配置 HTTPS 或换独立域名
🎯 核心记忆点
状态码选择
| 场景 | 使用 | 避免使用 |
|---|---|---|
| API 重定向 | 307/308 | 301/302 |
| 页面跳转 | 301 | 307 |
| HTTP → HTTPS | 307(首次)+ HSTS(后续) | 301 |
HSTS 配置原则
nginx
# ✅ 逐步启用(推荐)
add_header Strict-Transport-Security "max-age=86400"; # 1天测试
# 没问题后
add_header Strict-Transport-Security "max-age=31536000"; # 1年
# 确认所有子域名都支持 HTTPS 后
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";
# 极度确定后才 Preload
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload";
排查优先级
- 先看 Network 面板 - 90% 的问题这里能发现
- 检查 HSTS 缓存 -
chrome://net-internals/#hsts - 用 curl 验证 - 排除浏览器缓存干扰
- 查服务器配置 - Nginx/Apache 配置文件
记住:遇到重定向问题,先看 Network,再查 HSTS,最后改配置。