搜索全站
Google SEO 8 分钟阅读

301、302、307、308 的区别:重定向类型对 SEO 的影响

302 用久了权重传不过去。本文讲清 301/302/307/308 的语义差别与搜索引擎处理方式,给出 WordPress、Nginx、Apache 中的正确写法与排查命令。

U
UFO_PF 2024-06-25 · 阅读 8 分钟
30 GOOGLE SEO
阅读提示
本文约 3,082 字,预计阅读 8 分钟。文中命令与配置均经过实测,可直接参考执行。

引言:半年前做的一次跳转,排名一直没接上

有个站改版时把旧域名用 302 跳转到新域名,理由是”先试试,稳定了再改 301″。半年后新域名的排名始终上不去,旧域名的 URL 依然大量出现在搜索结果里。原因就出在这个 302 上——它告诉搜索引擎”这只是临时搬家”,于是旧 URL 一直被保留在索引中,权重不向新地址传递。

重定向状态码的选择不是技术细节,而是直接写进索引策略的指令。更麻烦的是,很多框架和插件的默认值并不是你想要的那一个:PHP 的 header('Location: ...') 默认发 302,WordPress 的 wp_redirect() 默认也是 302。如果不显式指定,你以为做了永久跳转,实际发出去的是临时跳转。

原理分析:四种状态码的语义与引擎处理

状态码 语义 是否传递信号 是否改变请求方法 典型场景
301 永久移动 是 可能变为 GET 域名迁移、URL 结构变更
302 临时移动 否 可能变为 GET A/B 测试、临时活动页
307 临时重定向 否 严格保持原方法 临时跳转且需保留 POST
308 永久重定向 是 严格保持原方法 API 永久迁移、保留 POST

关键点有两个:

一是信号传递。 Google 明确说明 301 会把排名信号传递给目标页;302 被长期使用时,Google 会”猜测”你可能想表达永久意图,但这种猜测不可靠、也不及时。所以永久迁移必须显式用 301(或 308)。

二是请求方法保持。 301/302 在历史上的实现允许把 POST 改成 GET,导致表单数据丢失;307/308 是后来新增的严格版本,强制保持原请求方法。对普通页面跳转影响不大,但对 API 接口和表单提交至关重要。

需要注意的另一类”假跳转”:用 <meta http-equiv="refresh"> 或 JS 的 window.location 实现的跳转。Google 会处理 meta refresh,但把它当作 301 还是 302 取决于延迟时间(0 秒近似永久,大于几秒按临时处理),可靠性远低于服务端跳转,能不用就不用。

保姆级实操

步骤 1:确认现有跳转的真实状态码。 浏览器会自动跟随跳转,看不出来,必须用命令行。

# 打印每一跳的状态码与 Location
curl -sIL https://old.example.com/page | grep -Ei "^(HTTP/|location:)"

步骤 2:永久迁移统一改成 301。 PHP 层用 wp_redirect() 时必须显式传第二个参数。

<?php
// WordPress 中正确的永久跳转写法(默认 302,必须显式指定 301)
add_action('template_redirect', function () {
    if (is_page('old-landing')) {
        wp_redirect(home_url('/new-landing/'), 301);
        exit;
    }
});

// 原生 PHP 写法:第三个参数才决定状态码,默认 302
header('Location: https://example.com/new/', true, 301);
exit;

wp_safe_redirect() 与 wp_redirect() 参数一致,但前者会校验目标域名是否在允许列表内(通过 allowed_redirect_hosts 过滤器控制),跳转外部域名时更安全。

步骤 3:服务器层优先于 PHP 层。 能用 Nginx/Apache 处理就不要进 PHP,省一次完整的应用启动开销,对 TTFB 也有帮助。

# Nginx:域名整体迁移
server {
    listen 80;
    server_name old.example.com;
    return 301 https://new.example.com$request_uri;
}

# 单页跳转,注意 301 与 302 的区别
location = /promo {
    return 302 https://example.com/campaign/2026-spring;
}

Apache 的写法:

# .htaccess
Redirect 301 /old-page https://example.com/new-page
RewriteRule ^blog/(.*)$ https://example.com/news/$1 [R=301,L]

步骤 4:需要保留 POST 方法时用 307/308。 站点的表单、Webhook 接收端临时迁移用 307,永久迁移用 308。

# 表单提交端点永久迁移,保留 POST 方法
location = /api/subscribe {
    return 308 https://api.example.com/subscribe;
}

步骤 5:清理跳转链。 一次跳转最理想,超过两次就开始损失信号且拖慢速度。用 Screaming Frog 的 “Redirect Chains” 报告或 httpstatus.io 检测,把 A→B→C 直接改成 A→C。

步骤 6:验证。 改完后用 curl -sIL 确认状态码与跳转次数,并在 GSC”网址检查”里看 Google 读到的最终地址。批量跳转的规划方法可参考 批量 301 重定向规划。

常见踩坑

  1. 案例: 某站 HTTP 跳 HTTPS 用了 302,且 http:// 版本带 www、https:// 版本不带 www,形成 http://www → https://www → https:// 的三跳链。改成一个 return 301 https://example.com$request_uri; 后,LCP 相关的重定向耗时从 1.1 秒降到 0,索引中的重复 URL 也消失了。
  2. 用 wp_redirect() 不传第二个参数,默认 302,以为做了永久跳转实则没有。
  3. 用 JS 的 window.location.href 做跳转,爬虫执行 JS 有延迟且可能不执行,索引更新极慢。
  4. 302 长期使用后改 301,信号传递需要数周才能体现,期间排名波动属正常,别反复改回去。
  5. 表单接口用 301 跳转,POST 被降级成 GET,参数全部丢失,用户提交失败。
  6. 把 302 当作”临时下线”手段,结果页面被判定为软 404 或重复内容,需要处理时可参考 404 与软 404 处理。
  7. 重定向目标自身又是一次重定向,形成循环,浏览器报 ERR_TOO_MANY_REDIRECTS。上线前必须逐条 curl 验证。

总结

选择标准一句话概括:永久变更用 301(需保留请求方法时用 308),临时变更用 302(需保留请求方法时用 307),其他实现方式(JS、meta refresh)都不作首选。行动清单:用 curl -sIL 盘点现有跳转状态码;把永久迁移全部改成 301;把多跳链压平成一跳;表单与 API 端点改用 307/308;上线后逐条验证。跳转看着简单,却是改版事故的第一高发区,值得花半天时间逐条核对。

U
UFO_PF作者

专注 WordPress 生态的实战作者,内容以「可复制、可验证」为第一原则。

留下你的想法

邮箱地址不会被公开。带 * 的为必填项。