站点从 Next 13 升到 15,metadata 里写 alternates: { canonical: '/post/1024' }。上线后 GSC 显示大量页面的规范网址是域名根,内页几乎全被合并。
一开始怀疑是「页面同时有旧版 head 里手写的 link,与新输出冲突」,查了一圈,方向不对。
排查方向其实有限,先把可能性排一排。metadataBase 没配置,相对 canonical 被解析成根路径。也可能是app 路由的动态段没把 slug 传进 generateMetadata。
少数情况下是中间件做了尾斜杠重写,canonical 解析时丢了路径。
动手时先看线上输出的 canonical
curl -s https://www.example.com/post/1024 | grep -o '<link rel="canonical"[^>]*>'
然后在根布局里补 metadataBase
export const metadata = { metadataBase: new URL('https://www.example.com') };
接着改成绝对地址输出
return { alternates: { canonical: `https://www.example.com/post/${slug}` } };
批量复验所有页面的 canonical
python check_canonical.py --sitemap sitemap.xml --expect-self
这类问题以前遇到过,但这次的触发条件和上次不一样。
恢复的判定其实很直接。所有内页的 canonical 都指向自身绝对地址,GSC 里「已提交但未编入索引」的数量一周内下降三分之一。
框架升级时 canonical 这类标签最容易被静默改坏,升级后必须抽一批页面看源码,而不是只看页面能不能打开。这类问题最好一次改到位,反复小改反而容易把原因搅混。
