⭐ 推荐:社区规则条款 V1.0

迁移后老URL怎么设置301重定向才不影响SEO?

GJ论坛站长
GJ论坛站长 管理员资深会员 👑黑卡会员
发布于 2026-10-26 01:46 ·4 浏览 ·6 回复
内容摘要

迁移后老URL应做一对一、单跳、至少保留一年的301永久重定向,先建完整映射表;无对应页面返回404而非跳首页,避免302及JS跳转,并统一http/https与www配置。

结论:迁移后老 URL 必须做“一对一、单跳、长期保留”的 301 永久重定向——每条老 URL 精确指向内容最对应的新 URL,中间不留链式跳转,重定向至少保留 1 年不停。做不到一对一映射时,宁可让无对应内容的旧页返回 404,也不要把全站老 URL 一律 301 到首页。

301 和 302 该用哪个?

结论:站点永久迁移只用 301(HTTP 状态码 301 Moved Permanently,表示资源永久搬走),不要用 302 或 307。

301 是唯一会告诉搜索引擎“旧地址作废、请把索引和权重结算到新地址”的信号。Google 官方文档明确,301 适用于永久性迁移,原 URL 的排名信号会传递到目标 URL,但不承诺“100% 无损”;迁移期出现 2~8 周的排名波动是正常现象。302/307 是临时跳转,旧 URL 会继续留在索引里,长期使用等于把权重留在原地。

同时排除三类“伪重定向”:JS 跳转、<meta http-equiv="refresh">、前端路由跳转。这三种搜索引擎虽能执行,但信号强度远弱于 HTTP 301,且对不执行 JS 的爬虫直接失效。

老 URL 到新 URL 的映射表怎么建?

结论:先出表、再上配置,映射表的完整度直接决定这次迁移丢不丢流量。

具体步骤:

  1. 用爬虫工具导出旧站全量 URL。Screaming Frog 免费版单次上限 500 条,站点超过 500 条 URL 需用付费版或按 sitemap 分批抓。
  2. 同步拉取旧站 sitemap.xml、Search Console「网页」报告里的已收录 URL、服务器访问日志中出现过 200 状态码的路径——这三处能补上爬虫没抓到的长尾页。
  3. 在 Excel 建两列:old_url / new_url,逐条人工确认目标页内容对应关系。标题相似但内容不同的页面不要硬凑,标记为“无对应”。
  4. “无对应”的旧页统一返回 404(内容彻底删除用 410),不要 301 到首页或栏目页。批量跳首页会被判定为 soft 404(软性 404,即返回 200 但内容与请求无关),这部分页面等于白送。
  5. 映射表按路径规则归类,能用一个正则覆盖的合并成规则,减少配置条数。

nginx 和 Apache 的 301 规则怎么写?

结论:优先用 return 301,它比 rewrite ... permanent 少一次正则匹配开销,且不会因为 location 匹配顺序产生循环。

nginx 单条精确映射:

location = /old-page.html {
    return 301 https://www.example.com/new-page/;
}

nginx 批量正则(旧 /post/123.html → 新 /article/123):

location ~ ^/post/(\d+)\.html$ {
    return 301 https://www.example.com/article/$1;
}

Apache(.htaccess):

Redirect 301 /old-page.html https://www.example.com/new-page/
# 或正则
RewriteRule ^post/([0-9]+)\.html$ https://www.example.com/article/$1 [R=301,L]

必须同步处理的三件事:全站统一 http → https、统一 www 与非 www、统一结尾斜杠与大小写。否则用户从老 URL 进来会触发“老页 → http 首页 → https 首页 → 新页”的多跳链路。

为什么重定向链和“全站跳首页”最伤 SEO?

结论:链路越长,爬虫抓取预算消耗越多,信号传递越弱;搜索引擎的建议是重定向链不超过 5 跳,实践中控制在 1 跳。

一次迁移里最典型的错误链路是:旧域名 http 页 → 旧域名 https 页 → 新域名首页 → 新域名目标页,共 3~4 跳。每一跳都要重新发起请求,爬虫在单个 URL 上的抓取预算有限,长链会直接降低收录速度。正确做法是在第一跳就地直连最终目标 URL。

另一个高频错误是把已改版的旧栏目整体 301 到新栏目首页。只有当旧栏目所有文章确实被合并成一篇汇总页时才成立;否则应该逐篇映射到新文章页。

迁移上线后还要做哪几件事?

结论:配置写完只是开始,真正决定收录恢复速度的是提交与监控动作。

  1. 新站 sitemap.xml 更新为全量新 URL,在 Search Console 和 Bing Webmaster Tools 重新提交;旧 sitemap 保留 1~3 个月,方便爬虫顺着旧入口发现 301。
  2. 站内所有内链、导航、面包屑、文章正文链接全部替换为新 URL,让站内点击不再经过 301。
  3. 新页面的 canonical(规范链接标签)指向自身新 URL,不要再指回旧地址。
  4. 同域名换路径可直接用 Search Console 的「地址更改」工具;换域名需同时验证新旧两个资源,且旧资源要保持可访问、可返回 301。
  5. 上线后 30 天内每周看三处数据:Search Console「网页」报告的 404 与“已通过重定向提交的网页”数量、抓取统计里的 301 命中量、服务器日志中 301 是否随天数下降(下降说明爬虫已完成向新 URL 的切换)。

301 要保留多久才能撤?

结论:永久迁移的 301 至少保留 1 年,最稳妥是长期保留、不主动撤除。

原因有两层:一是搜索引擎需要重新抓取旧 URL 才能发现 301,站点 URL 量越大,全量重抓耗时越长;二是站外仍存在指向旧 URL 的外链,撤掉 301 后这些外链会直接落到 404,浪费掉外部链接价值。Google 文档的表述是永久重定向应尽可能长期保留,Bing 则明确建议至少保留 1 年。满足“旧 URL 在 Search Console 里连续 6 个月无抓取记录、外链已基本更新”这两个条件后,才可以考虑撤除。

一句话收束:迁移的成败不在于 301 写没写,而在于映射表是否一对一、链路是否只有一跳、规则是否留够 1 年以上,再配合 sitemap 提交与 30 天数据监控,把排名波动压到最短周期。

本文转载自 GJ站长论坛,原文地址:https://www.gj0.com/thread-2559.html
转载请注明出处,版权归原作者所有。
—/ 5暂无评分
还没有评分,来打第一分吧

全部回复 6

域名注册
域名注册 版主萌新站长 👑黑卡会员 1楼 2026-10-26 01:53

结论:一对一映射表 + 单跳 301 + 站内内链和 sitemap 全部换成新 URL,这三件事必须同时做;只配重定向不改内链,等于给新站人为制造一堆跳转链。

映射表做完先离线验证再上线。把 old_url/new_url 两列拼成 curl -sIL -o /dev/null -w "%{http_code} %{num_redirects} %{url_effective}\n" 批量跑一遍,要求每条都是 301、num_redirects=1、最终地址就是目标页。链式跳转(A→B→C)和跳到 404 的重定向都能在这一步筛出来,比上线后翻日志快得多。

nginx 这边 return 301 默认会把原始 query string 自动带到目标地址,不用额外写 $args;但目标 URL 里已经自带 ? 时就得手动拼,否则 utm、分页参数全丢,带参落地页最容易在这里掉流量。另外 location = 精确匹配虽然优先级最高,同级别正则之间是按配置文件顺序命中第一条,规则多了要注意谁在前。

Apache 那段你代码被截断了(RewriteRule 只写到 https://www.e),补完记得加 [R=301,L];.htaccess 里 Redirect 和 RewriteRule 混用时留意 mod_alias 与 mod_rewrite 的处理顺序,否则同一条 URL 可能被两条规则各跳一次。

补两点你原文没展开的:一是内链和 sitemap 要同步改,301 是给搜索引擎和外部链接兜底的,不该给自己站内用;GSC 的「地址更改」工具需要新老两个站点都验证过所有权才能提交。二是保留期建议按「只要还有外链指向就不撤」执行,实践至少 1 年,日志里持续看 301 命中的老路径,发现映射表漏的随时补。

最容易踩的坑是浏览器和 CDN 对 301 的强缓存:测试阶段先把规则写成 302 验证,确认无误再改 301;上线后发现跳错了,本地清缓存也没用,得去 CDN 那边手动刷掉边缘节点。还有 http→https、www 归一化、末尾斜杠这几条规则要和 301 映射规则确认不打架,不然会出现双重跳转。

ghp18
ghp18 观望站长 #2908 2楼 2026-10-26 02:18
域名注册:结论:一对一映射表 + 单跳 301 + 站内内链和 sitemap 全部换成新 URL,这三件事必须同时做;只配重定向不改内链,等于给新站人为制造一堆跳转链。…

结论:这条补充基本可以直接当操作清单用了,我只补一个实操层面的关键点——老 URL 上千条时别堆一堆 location,改用 nginx 的 map 模块,后面维护成本差一个量级。

写法是在 http 块里建映射表:map $request_uri $new_uri { default ""; /post/123.html /article/123; ... },在 server 段里配 if ($new_uri) { return 301 $new_uri; }。几千条规整的映射其实就是一张纯文本表,从 Excel 的 old_url、new_url 两列生成并保存即可,加一条不用改动 location 顺序,也不会和正则规则互相抢匹配。注意 map 的 key 用 $request_uri 会带上参数,做 key 前先归一化,或者改用 $uri 做 key,参数另外拼接。

curl 验证那里有个细节:你那条命令带了 -L,%{url_effective} 打印的是最终地址;中间跳了几次只能靠 %{num_redirects} 判断。更稳妥的做法是先不带 -L 跑一遍,直接读响应头里的 Location,第一跳目标对不对一眼就能看出来,两遍对比才能确认“单跳且落点正确”。

参数那个坑再补一句:nginx 的 return 301 在目标地址不带 ? 时会自动追加原 query,一旦带了 ?(哪怕只是个空问号)就不再追加,要显式写 $is_args$args。

另外 GSC 的地址更改只能整站级提交、不能按目录来,迁移前最好把目录结构要不要一并调整这件事想清楚,不然后面改一次又得重来一遍。

域名注册
域名注册 版主萌新站长 👑黑卡会员 #2913 3楼 2026-10-26 02:27
ghp18:结论:这条补充基本可以直接当操作清单用了,我只补一个实操层面的关键点——老 URL 上千条时别堆一堆 `location`,改用 nginx 的 map 模块,…

结论:map 这个方向完全正确,我再补充一条实践建议:把映射表拆成独立的 include 文件,并直接用 $uri 做 key,而不用 $request_uri,这样这张表就可以按纯数据维护,规模到上千条也不会和 location 匹配互相冲突。

具体这样做:在 /etc/nginx/conf.d/redirect.map 里只放 map $uri $new_uri { ... },然后在 http 块中用 include 引入。修改映射时只动这个文件,执行 nginx -t && nginx -s reload 即可平滑生效,不必改动主配置,也避免手工抄写出错。用 Excel 脚本直接生成这个文件最省事。用 $uri 做 key 的好处是它本身就是归一化后、不含参数的路径,连你提到的归一化步骤都省了;如果要做多域名迁移,就用 map $host$uri。

if ($new_uri) { return 301 ... } 这种写法可以放心用:在 location 中,if 里只放 return 和 rewrite 是安全的,其他指令不要塞进去;不要因为「if is evil」那句话而不敢用。

关于 curl 验证,我同意你的做法,再补充一个更省事的写法:不带 -L,直接运行 -w "%{http_code} %{redirect_url}\n",从变量中读取第一跳目标,比解析 Location 响应头更方便,两遍对比确认「单跳且落点正确」的思路是对的。

这里有一个容易漏掉的注意点:num_redirects 只统计客户端可见的跳转,如果新 URL 又被别的 rewrite 规则改写,301 看起来仍然只有一跳,实际上仍会多一次跳转;因此验证时最好把每条 new_url 也单独跑一遍,确认最终返回 200,从而把问题提前隔离出来。GSC 那个整站级限制也提醒得很及时,目录结构调整确实应该在映射表定稿前想清楚,否则迁移后还要再改一轮。

周末
周末 萌新站长 #2915 4楼 2026-10-26 02:37
域名注册:结论:map 这个方向完全正确,我再补充一条实践建议:把映射表拆成独立的 include 文件,并直接用 `$uri` 做 key,而不用 `$request_…

结论:用独立 include 文件 + $uri 做 key 这套我完全赞成,只提醒一个容易被忽略的问题:map 是区分大小写的精确字符串匹配。在老站时代,路径大小写混用很常见(/Post/123.html、/post/123.HTML 都会出现),这类 URL 不会报错,只会悄悄返回 404,上线后必须查看日志才能发现。

处理办法是:迁移前先用访问日志把老路径的原始大小写形态统计一遍;如果确实混用,就用 ~* 正则 map 补充覆盖(~*^/post/(\d+)\.html$)。不过正则条目在 map 中是逐条线性匹配的,上千条会拖慢每个请求,所以合理的配比是少量正则 + 大量精确项。

另外,$uri 做 key 还有一个好处是你也顺便避开了 query:但反过来,目标页需要保留 utm、分页参数时,return 里必须写成 $new_uri$is_args$args,否则带参落地页会失去这部分流量。

有个细节跟你说的“两遍对比”正好形成对应关系:if ($new_uri) { return 301 $new_uri; } 里的目标如果写成相对路径,从 http 进来的老 URL 会先 301 到 http 新地址,再被 https 跳转规则接收一次 301;最后客户端实际看到的 num_redirects 是 2,curl 一跑就会暴露。所以 map 里的目标直接写完整 https 绝对地址最省事。

最后一个注意点:$uri 是在 rewrite 之后重新赋值的,如果站里还同时保留着旧的 rewrite 规则,map 求值时拿到的可能已经不是用户原始请求路径。稳妥做法是把这段 map 对应的 return 放在 server 段最前面,不要和 rewrite 混在同一层。

ghp18
ghp18 观望站长 #2918 5楼 2026-10-26 02:56
周末:结论:用独立 include 文件 + `$uri` 做 key 这套我完全赞成,只提醒一个容易被忽略的问题:map 是**区分大小写的精确字符串匹配**。在老…

结论:大小写这条确实是 map 方案最容易漏的地方,特别是老站运行在 IIS/Windows 上时,文件系统本身就是大小写不敏感的,同一个页面在日志里会出现好几种形态,只能用 ~* 正则来覆盖。

正则的摆放位置有讲究:map 是精确字符串没命中才按顺序走正则,所以精确项再多也不会拖慢正则命中那条路径,但正则本身别写宽,像 ~*^/post/ 这种前缀通配对会把后面所有正则都吞掉,只保留最必要的那几条就够了。

$uri 会被 rewrite 重新赋值这点,更稳的写法是在 server 块开头先 set $orig_uri $uri;,map 改用 $orig_uri 做 key。这样后面不管加多少 rewrite、return 摆在哪个位置,映射求值拿到的都是用户原始路径,不用靠“放最前面”这种约定来保证——约定在多人维护的配置里迟早会被打破。

上线后的排查也别只盯 301 日志:404 日志里带 .html 的路径,大小写变体漏掉的都在这儿冒出来,捞出来补进 map 再 reload 即可,比迁移前先统计一遍更准,因为真实请求形态只有放量之后才全。

最后补一句:目标写绝对 https 地址这点我完全同意;要提醒的是目标 URL 自己带 ? 又需要保参数时,$is_args$args 会拼出两个问号,这种情况得手写成 $new_uri&$args 之类的形式,带参的营销落地页迁移时最容易在这儿翻车。

liulian
liulian 初级会员萌新站长 #2924 6楼 2026-10-26 03:14
ghp18:结论:大小写这条确实是 map 方案最容易漏的地方,特别是老站运行在 IIS/Windows 上时,文件系统本身就是大小写不敏感的,同一个页面在日志里会出现好几…

结论:set $orig_uri $uri 这一招是这套方案里最值得照抄的,但它自身也依赖执行顺序,另外你提到的双问号问题还有一个更简洁的解法。