你输入 https://yourdomain.com,站点打开。再输入 https://www.yourdomain.com,同一个站也打开、内容一模一样。两个都返回 200。看着没问题,但对 Google 的去重机制、以及任何统计你外链的工具来说,你其实有两个内容相同的站在互相争夺权重。
最快的修法:选一个主机名作为 canonical,让另一个在主机/CDN 层返回 301 重定向到它(不是只加一个 HTML <link rel="canonical"> 标签)。canonical 标签只是告诉爬虫你的偏好;301 才真正把访客和外链权重收拢到一个 URL 上。一条命令确认是否修好:
curl -sI https://www.yourdomain.com | grep -i -E "http|location"
你想看到 301 以及一个指向 canonical 主机的 Location: 头。如果看到的是 200,说明重定向还没生效。
这是 www vs root redirect 的更难版本:那篇里有一个版本根本打不开;这里两个都能正常工作,所以接好重定向之后你还得清理收录和外链。
为什么这真的重要(不是表面问题)
yourdomain.com 和 www.yourdomain.com 是不同的主机名,所以除非你明确告诉搜索引擎,它们会被当成不同的 URL。没有 301 时:
- 外链被分到两个主机上,哪个都攒不满权重。
- Google 会自己挑一个 canonical(不一定是你想要的那个——见 Google 的 canonicalization 排查指南),Search Console 里的报表也会变乱。
- 分析统计、cookie、以及任何同源登录在两个主机之间可能表现不一致。
你属于哪一种情况?
先跑下面两条 curl,再对照原因。
| 你观察到的现象 | 最可能的原因 | 在哪修 |
|---|---|---|
两个主机都直接从你的主机返回 200 | 两个都作为独立域名加了,没配重定向 | 主机控制台(Vercel / Netlify / Firebase) |
两个都 200,服务器在 Cloudflare 后面(已代理) | 两条 DNS 记录都代理了,没配重定向规则 | Cloudflare Redirect Rules |
两个都 200,HTML 里有 canonical 标签 | 设了 canonical 标签但没有 HTTP 301 | 在主机/CDN 层加 301 |
两个都 200,自托管 | 一个 nginx/Apache server_name 同时服务两个 | 加一个重定向 server block |
一个返回 301,另一个 200 | 重定向已正确——把收录清理做完即可 | Search Console + 内链 |
诊断命令:
curl -sI https://yourdomain.com | head -5
curl -sI https://www.yourdomain.com | head -5
两个都是 HTTP/2 200 表示没有重定向。其中一个是 HTTP/2 301 并带 Location: 头,说明那一侧已经在重定向了。
常见原因
按命中率从高到低。
1. 主机里加了两个版本但没配重定向
你在 Vercel/Netlify 把 yourdomain.com 和 www.yourdomain.com 当成两个独立域名都加了。主机乐意都服务,默认不配重定向。
怎么判断:主机控制台 → Domains → 两个看起来都是对等的 “primary” 项。你需要的是恰好一个 primary、一个 redirect。
2. CDN 把两者都直接代理到源站
如果 Cloudflare(或别的 CDN)把两条 A/AAAA/CNAME 记录都设了代理,两个都到达源站、都返回内容。除非你加规则,CDN 不会重定向。
怎么判断:上面两条 curl -sI 都返回 200。在 Cloudflare 的 DNS 标签页里,两条记录都显示橙色 “Proxied” 云朵。
3. 主机支持两个绑定但不会替你推断 primary
有些主机允许你加两个名字,但要求你手动选 primary,不会替你假设要哪个。
怎么判断:主机文档写着”加两个,然后设其中一个为 primary”——而你加完两个就停了。
4. 设了 canonical 标签但没有 HTTP 重定向
你给每一页都加了 <link rel="canonical" href="https://yourdomain.com/...">。标签是给 Google 的提示,但访客还是看到他们输入的那个主机,原始外链也还是指向非 canonical 主机。
怎么判断:两个 URL 都返回 200(不是 301)。canonical 标签从不重定向。
5. 自托管 nginx/Apache 同时服务两个名字
老的共享主机或手写配置里,可能有一个 server_name yourdomain.com www.yourdomain.com; block 而没有重定向规则。两个名字都能用,于是产生重复内容问题。
怎么判断:SSH 进去看配置。如果 server_name 在同一个 block 里列了两个名字、且没有单独的重定向 server block,就是这条。
最短修复路径
第 1 步:选 canonical 主机
两个选择对 SEO 都中性——Google 已确认排名上没有差别。按技术因素来选:
- Apex(
yourdomain.com):URL 更短,前提是你的 DNS 提供商在 apex 上支持ALIAS/ANAME/CNAME 扁平化。DNS 规范禁止在 apex 记录上用普通CNAME,这也是有些主机引导你用 www 的原因。 - www(
www.yourdomain.com):CDN 配置最省事,因为www是普通子域、可以用普通CNAME。截至 2026 年 6 月,Vercel 明确建议把 www 设为 primary,正是出于这个原因(CDN 对进站流量有更多掌控)。
定好一次,写下来,并让所有内链、sitemap 条目和 canonical 标签都跟它保持一致。
第 2 步:在主机/CDN 层配重定向
Vercel — Project → Settings → Domains:
- 把
yourdomain.com和www.yourdomain.com都加上(加 apex 时会自动建议加上对应的 www)。 - 在非 canonical 那个域名上点 Edit,打开 Redirect to 下拉,选 canonical 主机。
- Vercel 自动签发一个
308/301级别的永久重定向。(Vercel 默认用308,它保留请求方法,搜索引擎对它和301一视同仁地当作永久重定向。)
Netlify — Site configuration → Domain management → Domains:
- 加两个名字。
- 把 canonical 那个设为 primary domain,另一个成为 domain alias。
- Netlify 自动把 alias 重定向到 primary。这种自动行为只覆盖 apex ↔ www;其他子域要手动配重定向规则。
Firebase Hosting — 在控制台里加第二个域名时,选 “Redirect to an existing site/domain”(重定向到已有站点/域名)并指向 canonical。若要走配置即代码,在非 canonical 站点的 firebase.json 里设一条 catch-all 重定向,然后用 firebase deploy --only hosting 部署:
{
"hosting": {
"redirects": [
{ "source": "**", "destination": "https://yourdomain.com", "type": 301 }
]
}
}
Cloudflare — Page Rules 已是旧功能,用 Redirect Rules。控制台路径:Rules → Templates → “Redirect from WWW to Root”(或 “Redirect from Root to WWW”)→ Create a Rule。要手动建的话,进 Rules → Redirect Rules → Create rule,用通配符:
When incoming requests match: https://www.yourdomain.com/*
Then redirect to URL (dynamic): https://yourdomain.com/${1}
Status code: 301
Preserve query string: On
注意现在的占位符是 ${1}(旧的 Page Rules 用的是 $1)。部署规则,并保持对应的 DNS 记录处于代理状态(橙色云朵),规则才会实际生效。
自托管 nginx — 把重定向拆成单独的 server block:
server {
listen 443 ssl;
server_name www.yourdomain.com;
return 301 https://yourdomain.com$request_uri;
}
然后用 nginx -t && systemctl reload nginx 重载。Apache 对应做法:在 www 的 VirtualHost 里用一条 Redirect 301 / mod_rewrite 规则。
第 3 步:验证重定向
curl -sI https://www.yourdomain.com | head -5
你想看到:
HTTP/2 301
location: https://yourdomain.com/
Vercel 返回的 308 也是对的。返回 200 就是重定向还没上线。再测一个深层路径,确认重定向会保留路径、而不只对首页生效:
curl -sI https://www.yourdomain.com/some-article/ | grep -i location
# 预期:location: https://yourdomain.com/some-article/
第 4 步:让 HTML canonical 标签保持一致
模板里的 canonical 必须在每一页都指向 canonical 主机:
<link rel="canonical" href="https://yourdomain.com/your-article/" />
绝不能指向 alternative 主机。重定向加一个相矛盾的 canonical 标签,会发出互相打架的信号。
第 5 步:修 Search Console(现代做法)
如果你把两个主机当成两个独立的 URL-prefix property 验证过,最干净的修法是给 yourdomain.com 加一个 Domain property。Domain property 会自动把 http/https、www、non-www 以及所有子域合并进一份统一报表,你就不用再跨两个 property 拼数据了。用 Google 给的 DNS TXT 记录验证一次即可。
旧的 URL-prefix property 想留就留(盯非 canonical 主机的索引下降很方便),但把 canonical 主机当作 primary。
第 6 步:确认 Google 选对了 canonical
打开 Search Console → URL Inspection,粘贴一个非 canonical 的 URL(例如 https://www.yourdomain.com/your-article/),看 “User-declared canonical” 和 “Google-selected canonical” 是否一致。301 被爬到之后,Google-selected 应收敛到你的 canonical 主机。Google 明确说过它可能选一个跟你声明不同的 canonical,所以这一步才是真正的证据——光看重定向不够。
合并是渐进的:大约 2–4 周内 Google 会重新抓取并把链接权重转到 canonical 上。在 Search Console → Indexing → Pages 里,非 canonical 的 URL 应逐步落入 “Alternate page with proper canonical tag” / “Page with redirect” 这些分类。
如何确认彻底修好了
- 对非 canonical 主机跑
curl -sI返回301/308,且Location:正确(首页和一个深层路径都要测)。 - canonical 主机直接返回
200(它不能重定向到自己——那会形成死循环)。 - URL Inspection 显示 Google-selected canonical = 你选定的主机。
- 2–4 周内,被收录的非 canonical URL 趋向归零。
哪些情况不是你操作错了
确实有几个主机的怪癖:Firebase 的逐站点模型、Cloudflare 的 apex-vs-subdomain 代理处理、以及在 apex 上不支持 ALIAS/ANAME 的 DNS 提供商。如果主机的行为跟它自己的文档矛盾,附上你的 curl -sI 输出提工单。
容易误判的情况
只加 <link rel="canonical"> 标签并不能阻止双服务——两个主机仍然都回 200。只有主机/CDN 层的 301/308 才能把真实流量和外链收拢。如果你”加了 canonical 标签”但两个 URL 还都能打开,说明修复没做完。
预防建议
- 任何新域名第一天就决定 www vs apex。
- 永远在主机/CDN 层做重定向,而不只是加 canonical 标签。
- 任何 DNS 或主机变更之后,用
curl -sI重新确认一个主机301到另一个。 - 一开始就用单个 Search Console Domain property,让合并自动完成。
- 团队管理的域名,在
DOMAIN.md里记下 canonical 选择。
FAQ
- www 还是 apex 对 SEO 更好? 排名没差别,Google 直接说过。按技术因素选(apex 需要
ALIAS/ANAME;www 用普通CNAME即可)。 - 我的主机返回
308而不是301,是不是错了? 不是。308是永久重定向,还会保留 HTTP 方法。Vercel 默认用它,搜索引擎在合并上把它等同于301。 301已经上线了,还需要 canonical 标签吗? 需要。301处理打到错误主机的访客和爬虫;canonical 标签强化你的选择,并覆盖带参数 URL 这类边角情况。- Google 多久才合并? 通常是 2–4 周的重新抓取。盯 URL Inspection 里的 Google-selected canonical,别靠猜。
- 以后能改 canonical 吗? 能,但意味着一条重定向链(老 canonical → 新 canonical)、canonical 标签更新、以及 4–8 周让 Google 完全切换。别随便切。
- 两个已经互相重定向、站却挂了,为什么? 你做出了重定向死循环(每个主机都指向对方)。canonical 主机必须返回
200,只能由非 canonical 主机做301。