0

Nginx return 308永久重定向参数保留配置:5个实战场景让你彻底搞懂308与301的区别

2026.06.01 | youres | 23次围观

前言

很多运维朋友在配置 Nginx 永久重定向时,通常第一反应就是用 return 301。但最近遇到一个典型场景:页面做了永久重定向后,Google Analytics 的 UTM 参数全丢了,流量归因直接失效。换成 return 308 之后,问题迎刃而解。

308 和 301 都是永久重定向,但两者在参数处理上的行为有本质区别。今天这篇文章就把这个问题彻底讲清楚。

一、308 和 301 的核心区别

1.1 规范层面的定义

  • 301 Moved Permanently:旧资源永久移动,POST 请求可以转为 GET(浏览器行为)
  • 308 Permanent Redirect:旧资源永久移动,方法不变(POST 保持 POST)

从 RFC 7538 定义来看,308 出现得比 301 晚,就是为了解决 301 在某些场景下会把 POST 偷偷转成 GET 的问题。

1.2 实际行为对比

特性301308
SEO 权重传递✅ 传递✅ 传递
查询参数保留❌ 默认丢失✅ 默认保留
POST 转 GET⚠️ 浏览器可能转✅ 不转
浏览器缓存✅ 缓存✅ 缓存
适用场景简单页面跳转API / 表单 / 参数敏感场景

二、Nginx return 308 默认参数行为

在 Nginx 中使用 return 308 最省心的一点是:查询参数默认保留,不需要额外处理。

# 最简写法,参数自动保留
server {
    listen 80;
    server_name old-site.com;
    return 308 https://new-site.com;
}

# 或者在 location 块中
location /old-page {
    return 308 https://new-site.com;
}

访问 https://old-site.com/old-page?utm_source=google&utm_medium=cpc 会自动跳转到 https://new-site.com/old-page?utm_source=google&utm_medium=cpc,参数完整保留。

三、5个实战配置场景

场景1:基础 HTTPS 永久跳转,参数全保留

server {
    listen 80;
    server_name www.example.com example.com;
    return 308 https://www.example.com;
}

适用于 HTTP 强制跳转到 HTTPS 的场景,UTM 参数、分页参数全部保留。

场景2:带条件的参数保留(只保留特定参数)

server {
    listen 80;
    server_name old.com;
    
    # 只保留 utm_ 开头的参数,丢弃其他
    if ( ~ "^/campaign\?(.*)$") {
        return 308 https://new.com/campaign?;
    }
    
    return 308 https://new.com;
}

这里用了正则捕获组 手动拼接参数,需要注意用 rewrite 配合 break 也能达到同样效果。

场景3:POST 请求跳转,参数和请求体都保留

location /api/legacy {
    return 308 https://new-api.com/api/v2;
}

308 保证了 POST 请求跳转到新地址后,Content-Type、请求体、方法都不变。这是它和 301 最大的使用区别。

场景4:多域名合并跳转

server {
    listen 80;
    server_name legacy-a.com legacy-b.com;
    
    # 通过变量判断来源域名,在跳转目标中替换
    set  "new-site.com";
    if (System.Management.Automation.Internal.Host.InternalHost = "legacy-a.com") {
        set  "new-site.com";
    }
    if (System.Management.Automation.Internal.Host.InternalHost = "legacy-b.com") {
        set  "new-site.com";
    }
    
    return 308 https://;
}

场景5:部分路径永久迁移,保留参数

location /blog/2024 {
    return 308 https://www.example.com/blog;
}

这里用了 来拼接查询参数, 在没有参数时是空字符串,有参数时是 ?,自动处理了参数有无的边界情况。

四、308 vs 301 vs 307 选型决策

很多人在 301 和 308 之间纠结,其实看一个决策树就够了:

  • 页面是 GET 请求(普通链接跳转)→ 优先选 301,兼容性好
  • 页面有 表单 / API(POST 请求)→ 必须选 308,方法不变
  • 需要 临时跳转(维护页、AB测试)→ 选 302307
  • 临时跳转 + POST 请求 → 必须选 307
  • 跳转后 参数敏感(UTM、追踪参数)→ 选 308,参数默认保留

五、常见问题排查

5.1 跳转后参数丢失

如果用了 return 308 但参数还是丢了,检查是否在 proxy_pass 之后跳转。proxy_pass 会消耗掉原始 URI,导致 获取不到原始路径。解决方法是用 set 先保存。

5.2 出现双重问号

有些配置写成 return 308 https://new.com/?,如果原 URL 本身带参数,就会出现 ?? 的问题。用 替代固定的 ? 即可:

return 308 https://new.com;  # ✅ 正确
return 308 https://new.com/?; # ❌ 双重问号

5.3 浏览器缓存导致跳转不生效

308 会被浏览器强缓存,如果修改了跳转配置后访问没反应,清一下浏览器缓存,或者用 curl -I 强制检查响应头。

六、验证命令

# 验证 308 跳转是否正确,参数是否保留
curl -I https://old-site.com/page?utm_source=google

# 查看响应头中是否有 Location 和 308 状态码
curl -I -L https://old-site.com/page?utm_source=google

# PowerShell 版本
Invoke-WebRequest -Uri 'https://old-site.com/page?utm_source=google' -MaximumRedirection 0

正常的 308 响应头应该类似:

HTTP/1.1 308 Permanent Redirect
Location: https://new-site.com/page?utm_source=google

总结

Nginx return 308 在参数保留方面比 return 301 更可靠,默认保留查询参数,不需要额外配置。对于有表单、API、UTM 追踪需求的场景,308 是更稳妥的选择。记住:简单页面用 301 没毛病,参数敏感场景优先 308。


相关文章:

版权声明

本文仅代表个人观点。
本文系AI辅助作者原创,未经许可,转载请保留原文链接。

发表评论