你在 Google 搜自己的品牌内容,结果显示的是 your-app.vercel.app 或 your-site.web.app,而不是 yourdomain.com。点进去是同一个页面。平台域名在你绑定自定义域名之前就被收录了,而 Google 不会自己迁移过去。
最快的修法(截至 2026 年 6 月): 让平台 URL 301 重定向到你的自定义域名,让两者不再互相竞争。在 Vercel 上只需一个设置:Project Settings -> Domains -> 编辑那个 *.vercel.app 域名 -> 把 Redirect to 设成你的自定义域名。再在每个页面吐一个指向自定义域名的 <link rel="canonical"> 兜底,然后回到 Search Console 重新检查一个示例 URL。自定义域名永远不会”自动获胜”——Google 需要一个明确信号(301、canonical 或 noindex)才会放弃旧域名。
为什么会这样(你属于哪一种)
自定义域名和平台域名提供的是逐字节相同的页面。对 Google 来说这就是同一篇文档对应两个 URL,所以它会挑一个 “Google-selected canonical”。如果平台 URL 起步早(有外链、有抓取历史、路径更短),Google 往往就保留它。按”真正原因”的命中率从高到低排:
| # | 原因 | 一行检查 | 命中的结果 |
|---|---|---|---|
| 1 | 先在平台 URL 上线,后绑自定义域名 | Google 搜 site:your-app.vercel.app | 出现已收录页面 |
| 2 | 没有 canonical,或 canonical 指向平台 URL | curl -s https://your-app.vercel.app/article | grep canonical | canonical href 里含 vercel.app |
| 3 | 平台 URL 没做重定向 | curl -sI https://your-app.vercel.app/ | 第一行是 200,不是 301 |
| 4 | 非生产的自定义域名泄漏(预览分支) | curl -sI https://staging-branch-domain/ | grep -i robots | 没有 X-Robots-Tag: noindex |
| 5 | Firebase web.app / firebaseapp.com 关不掉 | Google 搜 site:web.app yoursite | 有结果 |
| 6 | 外链还指向平台 URL | Ahrefs / Search Console “Links” 报告 | 大量引用页指向平台域名 |
有个细节常让人意外:Vercel 已经会自动给预览和生成的部署 URL 加上 X-Robots-Tag: noindex(也就是 *-git-branch-*.vercel.app 和那些哈希 URL),截至 2026 年 6 月如此。没有被自动保护的,是你那个稳定的生产别名 your-project.vercel.app,以及你绑到非生产分支上的任何自定义域名。所以如果索引里有 vercel.app URL,几乎都是原因 #1 里的生产别名——而不是某个漏网的预览。
最短修复路径
第 1 步:每个页面都吐指向自定义域名的 canonical
每页 <head> 都要有指向自定义域名的 canonical,哪怕请求是从平台域名进来的:
<link rel="canonical" href="https://yourdomain.com/article-path/" />
在 Astro 里从 site 来构造,这样不管请求由哪个别名服务,host 永远是你的域名:
---
// layout 里
const canonicalUrl = new URL(Astro.url.pathname, 'https://yourdomain.com').toString();
---
<link rel="canonical" href={canonicalUrl} />
canonical 是一个提示,不是命令——Google 可以推翻它(你会在 URL Inspection 里看到 “Google-selected canonical” 和你声明的不一致)。这正是第 2 步重要的原因:301 是指令,不是提示。
第 2 步:把平台 URL 重定向到自定义域名(真正的修法)
Vercel。 绑定自定义域名并不会移除或重定向 vercel.app 别名;两个都继续返回 200。在后台修:Project Settings -> Domains,在那个 *.vercel.app 域名上点 Edit,用 Redirect to 下拉框把它指向你的自定义域名(Vercel 会发 308 永久重定向,Google 当成 301 处理)。这就是 Vercel 官方推荐的、用来避免两个域名争抢重复内容的做法。
如果你更想放在代码里,vercel.json 里一条按 host 匹配的规则效果一样:
{
"redirects": [
{
"source": "/:path*",
"has": [{ "type": "host", "value": "your-app.vercel.app" }],
"destination": "https://yourdomain.com/:path*",
"permanent": true
}
]
}
保持 site 设好,canonical 和 sitemap 的 URL 才会正确:
// astro.config.mjs
export default defineConfig({
site: 'https://yourdomain.com',
});
Netlify。 在 Domain management 里把自定义域名设为 primary;Netlify 会自动把 *.netlify.app 子域名 301 到它。用 curl -sI 确认。
Firebase Hosting。 这个最麻烦。Firebase 设计上同时服务 *.web.app 和 *.firebaseapp.com,而 firebase.json 里的 headers 块会作用于所有绑定的域名——配置里没有 host 匹配,所以你没法只从 firebase.json 给 web.app 加 noindex。两个真正可行的办法:
- 运行时判断,只在请求 host 是 Firebase 默认域名时吐
noindex:
{(Astro.url.hostname.endsWith('.web.app') || Astro.url.hostname.endsWith('.firebaseapp.com')) && (
<meta name="robots" content="noindex" />
)}
- 或者用 Cloud Function / rewrite 在默认 host 前面挡一层重定向,让
web.app的请求 301 到你的域名。
无论哪种,在 Firebase 上真正出力的还是你的 canonical 标签(第 1 步)。
第 3 步:确认预览已经被 noindex(别过度折腾)
在 Vercel 上,预览和旧的生产部署 URL 已经自动带 X-Robots-Tag: noindex(2026 年 6 月),所以手动加规则通常是多余的。唯一的缺口是绑到非生产分支上的自定义域名——Vercel 不会给它加 noindex。如果你有个跑在预览分支上的 staging.yourdomain.com,自己加上这个 header,并按环境收口,确保生产环境永远不被碰到:
// vercel.json —— 只针对非生产别名
{
"headers": [
{
"source": "/(.*)",
"has": [{ "type": "host", "value": "staging.yourdomain.com" }],
"headers": [{ "key": "X-Robots-Tag", "value": "noindex" }]
}
]
}
用 curl -sI https://staging.yourdomain.com/ | grep -i robots 验证。
第 4 步:重新检查,别批量提交
在 Search Console 里,对几个你的自定义域名 URL 跑 URL Inspection,看 Google-selected canonical 这一栏。如果它现在显示 yourdomain.com,说明合并在生效,你基本只要等就行。如果还显示平台域名,说明你的 301 / canonical 还没传到 Google——用 curl 回头复查第 2 步。
你可以对自定义域名 URL 点 Request Indexing,但每个 property 每天大约只能提交 10-12 个 URL(Google 不公布确切数字,而且因站而异,截至 2026 年 6 月),所以把它花在最重要的页面上,其余的让它们靠 301 自己重新合并。不要把平台 URL 加成独立 property 再对它提交索引——那会告诉 Google 继续当成独立站追踪。
第 5 步:删掉平台 URL 的旧 GSC property(如果你建过)
如果你在上线时把 https://your-app.vercel.app/ 验证成了 Search Console property,把它从 property 列表里删掉。需要的话先导出数据;目的是不再把它当成独立站去喂养。
第 6 步:等待合并
301 和 canonical 上线后,Google 会在重新抓取时逐步丢弃平台 URL。site:your-app.vercel.app 的计数通常在 2-8 周内下降;头部页面最先动,因为它们被抓得最勤。
如何确认修好了
curl -sI https://your-app.vercel.app/返回301或308,且location:是你的域名。curl -s https://your-app.vercel.app/article | grep canonical显示 canonical 指向yourdomain.com。- Search Console URL Inspection 里,某个自定义域名 URL 的 Google-selected canonical 显示
yourdomain.com。 - 接下来几周内,
site:your-app.vercel.app的结果变少,品牌词 SERP 开始显示你的域名。
容易误判的情况
很多人以为加上自定义域名的那一刻它就接管了。并没有——两个域名都还活着,Google 会继续用它已经信任的那个。解药永远是一个明确信号:从平台域名发 301、指向自定义域名的 canonical、或平台域名上的 noindex。光绑域名什么都不会变。
哪些情况不怪你
Firebase 让你没法彻底退役 web.app / firebaseapp.com——它们是承重的默认域名。按 host 加 noindex 的 workaround 是现有最干净的办法,但它只是个 meta 标签信号,不是硬 301,所以合并可能比 Vercel 或 Netlify 慢——后两者你能直接控制重定向。
预防建议
- 任何项目第一天:把自定义域名设为 primary,并在发布或分享链接之前就把平台域名重定向过去。
- 每个模板里都从你的域名构造 canonical 标签,不管请求由哪个 host 服务。
- 绝不要在 Search Console 把平台 URL 验证成独立 property。
- 对任何非生产的自定义域名(staging / preview),自己加上
X-Robots-Tag: noindex——Vercel 只自动保护默认的预览域名。 - 每季度审一次
site:platform-url,尽早发现新收录的页面。
常见问题
- 能彻底禁用平台 URL 吗? 看平台。Vercel 和 Netlify 允许你把平台子域名 301 到自定义域名,对用户和爬虫来说就等于退役了。Firebase 的
web.app和firebaseapp.com设计上保持可访问——你只能noindex它们,删不掉。 - Google 会自己搞清楚吗? 最终会,但不可靠。没有 301 或 canonical,平台 URL 可能滞留好几个月。明确信号能把这缩短到几周。
- 我的 canonical 指向对的域名,但 Google 还是显示平台 URL,为什么? canonical 是 Google 可以推翻的提示,通常是因为平台 URL 外链或抓取历史更多。加上 301(第 2 步);重定向是指令,不是建议。
- 301 会伤排名或丢链接权重吗? 不会。永久重定向会把排名信号传给目标域名,这正是你要的——它把平台 URL 的权威合并到你的域名上。
- 旧 URL 多久会从搜索里消失? 一般是 301 和 canonical 上线后 2-8 周,抓取频繁的头部页面最快。你可以用 Request Indexing 推一把头部页面,但大头还是靠重定向自己完成。