200字
HTTP 重定向详解 🔄
2025-12-02
2025-12-02

🎯 什么是 HTTP 重定向?

重定向:服务器告诉浏览器 "你要访问的内容在另一个地址,请去那里访问"

用户请求 → http://old.com
           ↓
服务器响应 → "资源已移动到 http://new.com"
           ↓
浏览器自动 → 访问 http://new.com

📊 重定向的分类

按实现方式分类

1. 服务器端重定向(HTTP状态码)✅ 推荐
   └─ 301, 302, 303, 307, 308

2. 客户端重定向(HTML/JS)
   └─ <meta> 标签、JavaScript

按持久性分类

永久重定向(Permanent)
└─ 301, 308

临时重定向(Temporary)
└─ 302, 303, 307

🔢 常用状态码详解

1️⃣ 301 Moved Permanently(永久重定向)

含义: 资源已永久移动到新位置

特点:

✅ 搜索引擎会更新索引(旧URL权重转移到新URL)
✅ 浏览器会缓存重定向
✅ POST请求可能变成GET(历史遗留问题)

使用场景:

  • 网站更换域名

  • URL 结构永久性改变

  • HTTP → HTTPS(配合 HSTS)

  • 旧页面永久废弃

示例:

HTTP/1.1 301 Moved Permanently
Location: https://new.example.com/page

Nginx 配置:

server {
    listen 80;
    server_name old.example.com;
    return 301 https://new.example.com$request_uri;
}

2️⃣ 302 Found(临时重定向)

含义: 资源临时位于另一个位置

特点:

✅ 搜索引擎不会更新索引
✅ 浏览器不会缓存重定向
⚠️ POST请求可能变成GET(不符合规范但浏览器这样做)

使用场景:

  • 临时维护页面

  • A/B 测试

  • 临时活动页

  • 根据条件跳转

示例:

HTTP/1.1 302 Found
Location: https://example.com/temporary-page

应用示例(维护模式):

server {
    listen 80;
    server_name example.com;
    
    # 维护模式
    if (-f $document_root/maintenance.html) {
        return 302 /maintenance.html;
    }
}

3️⃣ 307 Temporary Redirect(临时重定向 - 严格版)

含义: 临时重定向,严格保持原请求方法

与 302 的区别:

302: POST → 可能变成 → GET ❌
307: POST → 保持为 → POST ✅

特点:

✅ 不改变请求方法
✅ 不改变请求体
✅ 适合 POST/PUT/DELETE 等请求

使用场景:

  • 表单提交重定向

  • API 临时迁移

  • 需要保持 POST 的场景

示例:

POST /api/old HTTP/1.1
Host: example.com

↓ 服务器返回

HTTP/1.1 307 Temporary Redirect
Location: https://example.com/api/new

↓ 浏览器重新发送

POST /api/new HTTP/1.1  ← 仍然是 POST!
Host: example.com

4️⃣ 308 Permanent Redirect(永久重定向 - 严格版)

含义: 永久重定向,严格保持原请求方法

与 301 的区别:

301: POST → 可能变成 → GET ❌
308: POST → 保持为 → POST ✅

特点:

✅ 不改变请求方法
✅ 搜索引擎更新索引
✅ 浏览器缓存重定向
✅ HTTP/1.1 新增(2015年)

使用场景:

  • API 永久迁移

  • 需要保持请求方法的永久跳转

示例:

location /api/v1/ {
    return 308 /api/v2$request_uri;
}

5️⃣ 303 See Other(查看其他位置)

含义: 重定向到另一个 URI,使用 GET 方法

特点:

✅ 明确指示浏览器使用 GET
✅ 常用于 POST 后重定向(PRG模式)
✅ 避免表单重复提交

使用场景:

  • POST 提交后跳转(防止刷新重复提交)

PRG 模式(Post-Redirect-Get):

步骤1: 用户提交表单
POST /submit
    ↓
步骤2: 服务器处理数据
保存到数据库
    ↓
步骤3: 返回 303
HTTP/1.1 303 See Other
Location: /success
    ↓
步骤4: 浏览器用 GET 访问
GET /success  ← 刷新页面不会重复提交!

代码示例(Express):

app.post('/submit', (req, res) => {
    // 处理表单数据
    saveToDatabase(req.body);
    
    // 303 重定向
    res.redirect(303, '/success');
});

📋 状态码对比表

状态码

名称

永久 / 临时

保持请求方法

SEO

缓存

主要用途

301

Moved Permanently

永久

❌ 可能改变

✅ 转移权重

域名迁移、URL 改变

302

Found

临时

❌ 可能改变

❌ 保留原页

临时跳转、AB 测试

303

See Other

临时

✅ 强制 GET

POST 后跳转 (PRG)

307

Temporary Redirect

临时

✅ 保持原样

API 临时迁移

308

Permanent Redirect

永久

✅ 保持原样

✅ 转移权重

API 永久迁移

🔧 实际配置示例

场景1:HTTP → HTTPS(301永久)

Nginx:

server {
    listen 80;
    server_name example.com www.example.com;
    
    # 永久重定向到 HTTPS
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name example.com www.example.com;
    
    # SSL配置...
    # HSTS头
    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
}

Apache:

<VirtualHost *:80>
    ServerName example.com
    Redirect 301 / https://example.com/
</VirtualHost>

场景2:www → 非www(301永久)

Nginx:

server {
    listen 80;
    server_name www.example.com;
    return 301 https://example.com$request_uri;
}

server {
    listen 443 ssl;
    server_name www.example.com;
    return 301 https://example.com$request_uri;
}

场景3:旧路径 → 新路径

Nginx:

location /old-blog/ {
    return 301 /blog$request_uri;
}

location = /old-page.html {
    return 301 /new-page.html;
}

# 正则匹配
location ~ ^/products/(\d+)$ {
    return 301 /items/$1;
}

Apache (.htaccess):

# 单个页面重定向
Redirect 301 /old-page.html /new-page.html

# 整个目录
RedirectMatch 301 ^/old-blog/(.*) /blog/$1

# 使用 mod_rewrite
RewriteEngine On
RewriteRule ^products/(\d+)$ /items/$1 [R=301,L]

场景4:维护模式(302临时)

Nginx:

server {
    listen 80;
    server_name example.com;
    
    set $maintenance 0;
    
    # 检查维护标志文件
    if (-f /var/www/maintenance.flag) {
        set $maintenance 1;
    }
    
    # 排除维护页面本身
    if ($uri = /maintenance.html) {
        set $maintenance 0;
    }
    
    if ($maintenance = 1) {
        return 302 /maintenance.html;
    }
    
    # 正常配置...
}

场景5:移动端检测(302临时)

Nginx:

server {
    listen 80;
    server_name example.com;
    
    # 检测移动设备
    if ($http_user_agent ~* (mobile|android|iphone|ipad)) {
        return 302 https://m.example.com$request_uri;
    }
    
    # 桌面端正常访问
}

场景6:语言/地区重定向(302临时)

Nginx:

server {
    listen 80;
    server_name example.com;
    
    # 根据 Accept-Language 重定向
    location = / {
        if ($http_accept_language ~* "zh") {
            return 302 /zh/;
        }
        if ($http_accept_language ~* "ja") {
            return 302 /ja/;
        }
        # 默认英文
        return 302 /en/;
    }
}

🎨 客户端重定向方式

虽然不推荐,但也需要了解:

1. HTML Meta 标签

<!-- 3秒后跳转 -->
<meta http-equiv="refresh" content="3;url=https://example.com">

<!-- 立即跳转 -->
<meta http-equiv="refresh" content="0;url=https://example.com">

缺点:

  • SEO 不友好

  • 用户体验差

  • 无法被爬虫正确处理

2. JavaScript 重定向

// 立即跳转
window.location.href = 'https://example.com';

// 或
window.location.replace('https://example.com');  // 不记录历史

// 延迟跳转
setTimeout(() => {
    window.location.href = 'https://example.com';
}, 3000);

缺点:

  • 依赖 JavaScript

  • 禁用 JS 的用户无法跳转

  • SEO 不友好

🧪 重定向链问题

什么是重定向链?

用户访问: http://example.com
    ↓ 301
跳转到: http://www.example.com
    ↓ 301
跳转到: https://www.example.com
    ↓ 301
跳转到: https://www.example.com/
    ↓
最终页面

问题:

❌ 增加页面加载时间(每次重定向 = 一次往返)
❌ 浪费爬虫配额
❌ 可能损失部分 SEO 权重
❌ 用户体验差

解决方案:

server {
    listen 80;
    server_name example.com www.example.com;
    
    # 一步到位!
    return 301 https://example.com$request_uri;
}

server {
    listen 443 ssl;
    server_name www.example.com;
    
    # 去除 www
    return 301 https://example.com$request_uri;
}

🔍 如何查看重定向

Chrome 开发者工具

1. 打开开发者工具(F12)
2. Network 标签
3. 勾选 "Preserve log"
4. 访问页面
5. 查看状态码 301/302/307/308
6. 点击请求查看 Location 头

cURL 命令

# 显示重定向
curl -I http://example.com

# 跟随重定向
curl -L http://example.com

# 显示所有重定向步骤
curl -L -v http://example.com 2>&1 | grep "< HTTP\|< Location"

在线工具

⚠️ 常见问题与最佳实践

1. 选择正确的状态码

永久性改变 → 301 或 308
临时性改变 → 302 或 307
POST后跳转 → 303

2. 避免重定向循环

# ❌ 错误示例
location / {
    return 301 /page;
}
location /page {
    return 301 /;  # 形成循环!
}

# ✅ 正确做法
location / {
    return 301 /page;
}
location /page {
    # 正常处理
}

3. 处理查询参数

# 保留查询参数
return 301 https://new.com$request_uri;

# 添加新参数
return 301 https://new.com$request_uri?source=redirect;

# 移除所有参数
return 301 https://new.com$uri;

4. 相对路径 vs 绝对路径

# ✅ 推荐:绝对路径
Location: https://example.com/new-page

# ⚠️ 相对路径(可能有兼容问题)
Location: /new-page

5. 监控重定向性能

// 使用 Performance API
const redirectCount = performance.navigation.redirectCount;
console.log(`重定向次数: ${redirectCount}`);

📈 SEO 影响

301 vs 302 的 SEO 差异

301 永久重定向:
✅ 90-99% 的权重转移
✅ 搜索引擎更新索引
✅ 旧 URL 最终从索引中移除

302 临时重定向:
❌ 权重不转移
❌ 搜索引擎保留旧 URL
❌ 可能导致内容重复问题

Google 官方建议

  1. ✅ 网站迁移使用 301

  2. ✅ 保持重定向至少 6 个月

  3. ✅ 更新内部链接指向新 URL

  4. ✅ 在 Google Search Console 提交地址更改

  5. ❌ 不要使用 JavaScript 重定向

🎯 总结

决策树

需要重定向?
    ↓
是否永久?
    ├─ 是 → 需要保持请求方法?
    │         ├─ 是 → 308
    │         └─ 否 → 301
    └─ 否 → 什么场景?
              ├─ POST后跳转 → 303
              ├─ 需保持方法 → 307
              └─ 普通临时 → 302

最佳实践清单

✅ 优先使用服务器端重定向
✅ 减少重定向链(最多1-2次)
✅ 使用绝对 URL
✅ 正确选择状态码
✅ 监控重定向性能
✅ 配合 HSTS 使用(HTTPS)
✅ 更新 sitemap 和内部链接
❌ 避免重定向循环
❌ 避免过多客户端重定向

快速记忆口诀

301永久换,SEO权重传
302临时用,原址仍保留
303表单提,POST变GET妙
307临时严,方法不能变
308永久严,既久又不变

评论