重复域名版本被收录:http / https / www / non-www

Google 把四个版本都收录了,链接权重被分成四份。用平台层 301 + canonical 把它们合并成一个的迁移方案。

site:yourdomain.com 返回 http://yourdomain.com/articlehttps://yourdomain.com/articlehttp://www.yourdomain.com/articlehttps://www.yourdomain.com/article 混在一起——四个 URL 服务完全相同的内容。每个变体多年来各自攒了一部分外链,但在 Google 眼里它们像是四个互相竞争的稀薄近似页,而不是一个强力页面。

最快修法: 选定一个 canonical 主机(比如 https://yourdomain.com),然后在平台/服务器层让另外三个返回 301 重定向到它——而不是只加一个 rel="canonical" 标签。rel="canonical" 标签只是提示(hint),不是规则;真正强制合并的是 301。再加上 HSTS、把 sitemap 和内链都指向 canonical,然后等 4–12 周让 Google 跟随重定向、合并权重。

本文把 HTTPS 没强制www 与 non-www 都能独立打开 整合成一个迁移计划。

先判断你属于哪一类

先跑这两个检查——它们直接告诉你到底缺哪个重定向:

# 1. 四个变体各自返回 200(坏)还是 301(好)?
for u in http://yourdomain.com https://yourdomain.com \
         http://www.yourdomain.com https://www.yourdomain.com; do
  echo "$u -> $(curl -s -o /dev/null -w '%{http_code} %{redirect_url}' "$u")"
done
你看到的含义怎么修
任意 http:// 返回 200HTTPS 没强制第 2–3 步(301 + HSTS)
apex 和 www 在 HTTPS 下都返回 200没有主机重定向第 2 步(选一个,另一个 301)
所有非 canonical 变体都已 301重定向没问题,是索引滞后 / 历史遗留问题第 4–8 步(信号 + 耐心)

然后确认 Google 实际怎么认。在 Search Console 里对某个非 canonical 变体跑 URL Inspection 工具,看 Page indexing → Google-selected canonical。如果它和你的 User-declared canonical 不一致,说明 Google 在覆盖你的标签——因为重定向或其它信号缺失或冲突。(注意:live test(实时测试)永远不显示 Google-selected canonical,只有已收录的结果才显示。)

常见原因

按命中率从高到低。

1. 站早于 HTTPS-by-default 时代,http 从没被重定向

大约 2018 年前上线的站常常原生服务 http。后来才补上 HTTPS,但 http 仍以 200 应答、没有强制重定向,于是多年外链都积在这个不安全的变体上。

怎么判断site:yourdomain.com 返回 http:// URL;上面的 curl 循环里 http:// 返回 200 而不是 301

2. www 和 apex 都服务内容

主机同时暴露了两个主机名,且没配主机层重定向。

怎么判断curl -sI https://yourdomain.comcurl -sI https://www.yourdomain.com 都返回 HTTP/2 200

3. 多年外链用了不一致的版本

哪怕现在强制了 HTTPS,第三方站仍链向老的 www/non-www 变体。Google 索引里还留着过去抓取时的那些 URL 映射。

怎么判断:外链报告(Ahrefs、Majestic,或 Search Console → Links → External links)显示入链分散在多个主机/协议变体上。

4. CDN 直接服务四个变体

没配 canonical 重定向规则的 CDN 或代理,会从缓存应答每一个变体。

怎么判断:检查 CDN 的 redirect/rewrite 规则。一条都没有,四个主机名就都直通回源。

5. 每个变体各自 self-canonical

http://yourdomain.com/article canonical 指向自己;https://www.yourdomain.com/article canonical 也指向自己。没有重定向时,四个都 self-canonical,Google 没有任何信号去统一它们。

怎么判断:对每个变体 view-source。如果四个都声明不同的 self-canonical,就没有赢家。

6. sitemap 列了多个变体

sitemap 里 httphttps 混着,或 www 和 non-www 混着。由于 sitemap 收录本身就是一个(较弱的)canonicalization 信号,这会主动把局面搅浑。

怎么判断grep -oE 'https?://[^<]+' sitemap.xml | sed -E 's#(https?://[^/]+).*#\1#' | sort -u——应该只打印出一个 origin。

最短修复路径

第 1 步:决定 canonical 主机

选一个并写下来:

  • https://yourdomain.com/(apex),或
  • https://www.yourdomain.com/(www)

SEO 上没有区别。实用的取舍:www 是 CNAME,更容易指向 CDN,也能避开 apex flattening 的怪问题;apex 更短、印刷展示更友好。

第 2 步:另外三个 301 重定向到 canonical

每个非 canonical 变体都必须以 301(永久)应答——不是 302、不是 meta-refresh——并保留路径:

到(示例:apex 为 canonical)
http://yourdomain.com/*https://yourdomain.com/[path]
http://www.yourdomain.com/*https://yourdomain.com/[path]
https://www.yourdomain.com/*https://yourdomain.com/[path]

各平台说明:

  • Vercel: 添加两个域名,把其中一个设为 primary;Vercel 会自动 301 其余的。见 Vercel domain redirects
  • Cloudflare: 用 Redirect Rule 或 Bulk Redirects(Page Rules 已是 legacy)。协议这一层开 Always Use HTTPS
  • Nginx: 在非 canonical 的 server 块里写 return 301 https://yourdomain.com$request_uri;
  • Firebase Hosting:firebase.json 里写 redirects,再配一个 canonical 自定义域名。

第 3 步:加 HSTS

从 canonical 主机发出这个响应头:

Strict-Transport-Security: max-age=63072000; includeSubDomains; preload

这会让浏览器以后访问时完全跳过 http。要日后进 HSTS preload 列表,这个头需要 max-age 至少 31536000(一年)、includeSubDomainspreload;每个子域都要提供有效 HTTPS,且每个 http 请求都要 301(不能是 302)到 HTTPS。务必稳定运行一段时间后再提交——preload 很难撤销。

第 4 步:内链指向 canonical

# 在代码库里找硬编码的非 canonical 或协议相对 URL
grep -rnE "http://yourdomain\.com|//www\.yourdomain\.com" src/ public/

内链是一个合并信号,所以一个漏网的 http://www 链接会拖后腿。导航、页脚、正文里都用绝对的 canonical URL。

第 5 步:sitemap 只用 canonical URL 重新生成

每页一条,都在 canonical 主机上。删掉残留的 http 或非 canonical 主机的条目,然后在 Search Console 重新提交。

第 6 步:每页 self-canonical 到 canonical 主机

<link rel="canonical" href="https://yourdomain.com/article/" />

用绝对 URL,并让尾斜杠用法与服务器实际服务的保持一致(/article/article/ 不匹配又会造出一个新的重复)。

第 7 步:只有真正换域名时才提交 Change of Address

Change of Address 工具是用于在不同域名之间搬家的(old.comnew.com),不是用来统一同一域名上的 http/https/www 的——主机/协议合并完全靠第 2 步的 301 处理。如果你同时还要换可注册域名:Search Console → Settings → Change of address,且新 property 必须已验证。截至 2026 年,Google 建议对所有旧变体(apex、www,以及任何子域)都提交请求,哪怕你没在用。信号会前转 180 天,所以重定向至少保留这么久。见 Site moves with URL changes

第 8 步:等 4–12 周并监控

Google 要重新抓取每个变体、看到 301、再合并权重——不是即时的。盯着看:

  • Search Console → Pages(Indexing): 非 canonical 变体应陆续进入 “Page with redirect” 这一桶。
  • URL Inspection: 对某个非 canonical URL,Google-selected canonical 现在应该等于你的 canonical 主机。
  • Performance: 总点击数应保持平稳或上升,因为分散的流量被合并到一个 URL。

怎么确认修好了

  1. “先判断你属于哪一类” 里的 curl 循环显示每个非 canonical 变体都 301 到 canonical,且路径被保留。
  2. curl -sI https://yourdomain.com | grep -i strict-transport 返回你的 HSTS 头。
  3. 对老变体跑 URL Inspection,报告 Google-selected canonical = 你的 canonical 主机(只有已收录的 URL 才看得到,所以会比重定向滞后几周)。
  4. site:yourdomain.com 越来越多只返回 canonical URL。老变体在索引里还会逗留几周——这是正常的,不是退步。

容易误判的情况

加了 <link rel="canonical"> 就以为大功告成。这个标签是 Google 可以忽略的提示;两个版本仍以 200 应答、继续被收录。平台层的 301 才是强制合并的强信号。按 Google 的 canonicalization 文档,重定向和 HTTPS-vs-HTTP 都与 canonical 标签、sitemap 一起起作用。

哪些情况可能不是你操作错了

即使所有修复都到位,老的已收录变体在 Google 重新抓取期间仍会持续几周。不用为 site: 查询里还出现的每个老 URL 焦虑,也不要用 URL Removal 工具去 “清理”——它会把所有版本(包括你的 canonical)都隐藏掉,而且对合并毫无帮助。

预防建议

  • 任何新站第一天就强制 HTTPS 并选定 www-vs-apex。
  • canonical 标签、sitemap、OG 标签、JSON-LD 都用绝对 canonical URL。
  • 任何基础设施或 DNS 变更后,重跑一遍 curl 循环,确认所有变体仍 301 到 canonical。
  • 每季度审外链;对指向非 canonical 变体的高价值链接,可行时请对方更新(301 本就会前转权重,所以这是锦上添花,不是救火)。

FAQ

  • www 还是 non-www——SEO 上有差吗? 没有。选一个并保持一致。www 更容易指向 CDN(它是 CNAME);apex 是更短的 URL。
  • Google 真的会合并链接权重吗? 会,通过 301——通常 4–12 周。指向非 canonical 变体的外链通过重定向继续传递权重。
  • http 转 https 需要用 Change of Address 工具吗? 不需要。同一域名,只是协议/主机变化——301 就能搞定。Change of Address 只用于搬到不同的可注册域名。
  • 为什么 Search Console 仍显示 “Duplicate, Google chose a different canonical than user”? 信号冲突:缺重定向、内链指向了错的变体、或 sitemap 列了多个主机。先修重定向(第 2 步),再对齐内链和 sitemap。
  • 302 重定向够用吗? 不够。用 301(永久)。302 表示临时搬家,不能可靠地前转权重,还会让你没资格进 HSTS preload。
  • 主机不让我重定向 apex,怎么办? 在前面放一个 CDN/代理(Cloudflare Redirect Rules,或 Vercel/Netlify 的域名)来发 apex 的 301,因为很多 DNS 服务商无法直接重定向裸 apex。

相关阅读

标签: #域名 #DNS #SSL #排查 #重复域名