site:yourdomain.com 返回 http://yourdomain.com/article、https://yourdomain.com/article、http://www.yourdomain.com/article、https://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:// 返回 200 | HTTPS 没强制 | 第 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.com 和 curl -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 里 http 和 https 混着,或 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(一年)、includeSubDomains 和 preload;每个子域都要提供有效 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.com → new.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。
怎么确认修好了
- “先判断你属于哪一类” 里的 curl 循环显示每个非 canonical 变体都
301到 canonical,且路径被保留。 curl -sI https://yourdomain.com | grep -i strict-transport返回你的 HSTS 头。- 对老变体跑 URL Inspection,报告 Google-selected canonical = 你的 canonical 主机(只有已收录的 URL 才看得到,所以会比重定向滞后几周)。
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。