必须写在 里,放错位置等于没写;href 必须是绝对 url,且协议、域名、路径末尾斜杠须与目标页真实返回 url 逐字节一致,参数需按语义过滤,干扰型(如 utm_*)剔除,语义型(如 page、q)保留。

link rel="canonical" 必须写在 里,放错位置等于没写
搜索引擎只解析 HTML 初始源码的 区域,不会执行 JavaScript,也不读取 中的 <link>。你用 document.head.appendChild() 动态插入的 <link rel="canonical">,对 Google 来说根本不存在。
常见失效场景包括:
- 把标签塞进
开头、注释里,或 SSR 模板中误写在<div> 内部 <li>Next.js 里用了 <code>router.asPath或router.fullPath而不是router.pathname,导致 href 带了 query 参数或 hash - CMS 主题和 SEO 插件各自输出一个,页面出现两个
<link rel="canonical">,信号冲突直接被忽略 -
<link rel="canonical" href="/article/123">—— 相对路径,在 HTTP/HTTPS 环境下解析结果不同 -
<link rel="canonical" href="//example.com/article/123">—— 协议相对,CDN 回源时 host 头被改写可能指向错误源站 -
<link rel="canonical" href="http://example.com/article/123">—— HTTPS 站点用 HTTP,被视为不安全跳转 - 协议(
https://)不能省 -
www和非www是两个不同站点,选一个并全站统一 - 路径末尾斜杠必须与目标页真实返回的 URL 一致(
/article/≠/article),否则可能触发 301 跳转或 404,导致 canonical 失效 - 干扰型参数(如
?utm_source=xxx、?ref=abc、?sort=date)必须剔除 - 语义型参数(如
?page=2、?q=foo、?category=tech)通常应保留——第 2 页不是第 1 页的副本,它有独立索引价值 - PHP:用
parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH)提取干净路径,再拼上$_SERVER['HTTP_HOST'] - Next.js:在页面组件中通过
useRouter()获取router.pathname,手动过滤router.query中的 tracking 类参数 - Nuxt 3:在
useHead()中基于route.path构造,不要用route.fullPath - 在
<meta name="robots" content="noindex">的页面上设 canonical,搜索引擎可能直接忽略 canonical - 对已 301 跳转的页面,再设 canonical 指向跳转前地址,属于信号矛盾
- 全站所有页面 canonical 都指向首页,内页权重会被清零
验证方法:右键 → “查看网页源代码”,搜索 rel="canonical",确认它唯一、闭合、且严格位于 标签内。
href 必须是绝对 URL,相对路径或协议相对路径全都不行
href 值漏掉协议或域名,爬虫就无法准确定位“权威版本”。以下全是错的:
正确写法只有一种:<link rel="canonical" href="https://www.example.com/article/123">。注意三点:
动态页面生成 canonical 时,参数过滤要分清语义和干扰
判断标准就一个:这个参数是否改变了页面主体内容?
实操建议:
canonical 不能和 noindex 或 301 混用
它只是给搜索引擎的一条明确建议,不是开关,也不是重定向。混用会引发逻辑冲突:
目标 URL 必须返回 HTTP 200 状态码,不能是 301/302 跳转链中的中间页,也不能是 404。上线后务必用 Google Search Console 的“URL 检查”工具验证是否识别出规范版本。
最常被忽略的其实是路径末尾斜杠和协议一致性——这两个细节在本地开发或测试环境里往往看不出问题,但一上 CDN 或多层反代,就会因 host 头、协议协商或重写规则而悄然失效。











