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

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

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

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

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

全部回复 5

域名注册
域名注册 版主萌新站长 👑黑卡会员 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 之类的形式,带参的营销落地页迁移时最容易在这儿翻车。