本文要解决什么?
重复页不是多写一个 canonical 标签就能完全解决。把规范路径、历史跳转、站点地图和黑盒校验放进统一契约,减少 SEO 规则打架。
一份业务事实,不应该对应两条正式 URL
一个企业 Agent 既放在 /products/...,又放在 /agents/...,再做一条独立的开发落地页,如果三条页面都输出 index,follow 与不同的自规范地址,Google 就需要在它们之间判断重复程度。更合理的做法是先指定真正服务用户的正式网址,再统一处理其他入口。
业务内容对象可以被不同模块引用,但发布给搜索引擎时,每个搜索意图应尽量有一个明确、可维护的核心页面。要保留多个页面,必须给它们不同的内容职责,而不是只改标题。
四层职责:谁拥有哪项规则
内容模型负责回答“这个实体的正式路径是什么”;Next.js 页面使用该路径输出 Canonical;Sitemap 从同一模型投影可索引页面;旧网址只做一次永久跳转。主机名和 HTTPS 收敛交给反向代理,不再在 React、Next middleware 和 Nginx 各做一遍决定。
- 内容层:canonical path 作为单一事实,不靠组件猜测 URL。
- 路由层:旧路径 → 正式路径,禁止重定向链和环。
- 展示层:Title、H1、正文与结构化数据表达同一个实体。
- 测试层:从真实 HTTP 响应核验契约,而不是只读 TypeScript 配置。
一个可审查的重定向契约
对于已弃用页面,Next.js 的永久重定向通常返回 308。选择 301 或 308 应符合实际路由与方法语义,关键在于它是否永久、目标是否唯一、能否稳定到达。下面是精简的路由映射示例,不是多套业务裁决器。
export const redirects = [
{ source: '/old-agent', destination: '/agents/enterprise-ai-agent', permanent: true },
{ source: '/old-seo', destination: '/seo', permanent: true },
]
// next.config.mjs 中的 redirects() 直接 return redirects让测试访问页面,而不只是检查配置
真实测试应从 Sitemap 中取出全部 <loc>,逐个请求响应并核对 Canonical 自指、页面是否可索引;再遍历全部跳转规则,确认来源不在 Sitemap、目标属于规范页面、没有第二跳。只有三条示例跳转受测试保护,不能说明剩下十几条永远安全。
同时要给最核心的网址写独立的业务断言,避免配置与测试共享同一个错误目标时仍然一起通过。
- Sitemap 不出现重复 URL、旧路径、带参数链接。
- 正式页面 200,且恰好一个正确 Canonical。
- 每个历史路径都返回 301/308,Location 直接指向最终规范路径。
- 目标不能再出现在旧路径集合中,排除重复跳转。
- 部署后对公开网站重复运行同一份合同测试。
最后仍然要核对部署和 Google Search Console
构建产物全绿不等于 Nginx、CDN 和运行进程已经使用该提交。上线时应保留可核验的版本号,检查实际站点响应,并观察真正的 Googlebot 抓取日志。Sitemap 是规范化信号,不是强制索引指令。