rel=canonical 怎麼用?重複內容與網址正規化
同一份內容常常有 多個可以打開的網址。canonical 用來從中指定「哪一個才是正式版本」,避免搜尋引擎把它們當成不同的頁面。
<link rel="canonical" href="https://example.com/seo/indexing-canonical">重複內容的六種來源
多數重複內容不是刻意造成的,而是網址設計的副作用。
| 來源 | 例 |
|---|---|
| 通訊協定 | http://example.com/a 與 https://example.com/a |
| www 前綴 | example.com/a 與 www.example.com/a |
| 尾斜線 | /about 與 /about/ |
| 大小寫 | /About 與 /about |
| 查詢參數 | /products?sort=price、/products?utm_source=fb |
| 多重路徑 | 同一個商品掛在 /shoes/x 與 /sale/x 兩個分類下 |
追蹤參數是最容易忽略的一種
行銷活動的 utm_source、fbclid、gclid 都會產生新的網址。使用者分享帶參數的連結、其他網站也照著連過來,那個版本就有機會被獨立收錄。
自我參照的 canonical 剛好能解決這件事。
每一頁都寫自我參照
這是成本最低、效益最明確的一項
<!-- 在 https://example.com/about 這一頁 -->
<link rel="canonical" href="https://example.com/about">指向自己看起來多餘,實際上做了兩件事:
- 明確宣告 這一頁就是正式版本,不必讓搜尋引擎猜。
- 吸收參數變體:
/about?utm_source=fb也會輸出同一個canonical,所以它不會被當成獨立頁面。
實作上不要逐頁手寫,交給框架自動產生。多數框架都有在建置階段介入頁面檔頭的機制,共通的作法是由路由算出絕對網址,一次套用到全站:
// 建置時每個頁面執行一次,回傳要寫進檔頭的標籤
function pageHead(route) {
// 去掉副檔名與結尾的 index,讓路徑與實際網址一致
const path = route.replace(/index\.\w+$/, '').replace(/\.\w+$/, '');
const url = `${domain}/${path}`;
return [
['link', { rel: 'canonical', href: url }],
['meta', { property: 'og:url', content: url }],
];
}domain 要來自環境變數,測試機與正式機各自指向自己的網域,否則測試機的頁面會把正式機宣告成正式版本。
手寫最大的風險是複製貼上
逐頁手寫時,最常見的意外是複製了上一頁的 frontmatter 卻忘了改網址,結果十個頁面的 canonical 全指向同一個網址,等於主動要求搜尋引擎不要收錄其中九頁。
這種錯誤非常難發現,因為頁面本身完全正常。
三個要求
| 要求 | 說明 |
|---|---|
| 絕對網址 | 相對路徑雖然解析得了,但官方不建議,要寫完整的 https://example.com/about |
| 一頁只能一個 | 出現多個 canonical 時搜尋引擎會全部忽略 |
| 目標必須回傳 200 | 指向 404 或轉址的網址會被忽略 |
<!-- 不建議:相對路徑,解析得了但容易出錯 -->
<link rel="canonical" href="/about">
<!-- 無效:一頁兩個 -->
<link rel="canonical" href="https://example.com/about">
<link rel="canonical" href="https://example.com/about/">
<!-- 正確 -->
<link rel="canonical" href="https://example.com/about">它是提示,不是命令
搜尋引擎可能不採用您指定的版本
canonical 只是 其中一個訊號。當內部連結、網站地圖 或轉址都指向另一個網址時,搜尋引擎可能判斷您指定錯了而選擇別的版本。
Search Console 的網址檢查會顯示「使用者宣告的正規網址」與「Google 選擇的正規網址」兩欄,不一致就代表您的宣告沒被採納。
要讓它被採納,所有訊號必須一致:
| 訊號 | 該指向 |
|---|---|
canonical | 正式版本 |
| 站內連結 | 正式版本(不要連到參數版本) |
| sitemap | 只列 正式版本 |
| 轉址 | 非正式版本轉到正式版本 |
hreflang | 各語言版本的正式網址 |
和 301 轉址怎麼選
canonical | 301 轉址 | |
|---|---|---|
| 使用者看得到舊網址嗎 | 看得到,兩個都能開 | 看不到,會被導走 |
| 強度 | 提示 | 命令 |
| 適合 | 兩個網址都必須能開 | 舊網址不需要存在 |
判斷方式很簡單
問一句話:使用者有需要看到那個舊網址嗎?
- 不需要 → 用 301 轉址,更明確也更有效。
- 需要 → 用
canonical。
「需要」的典型情況:商品同時掛在兩個分類下、列表頁的排序與篩選版本、印刷版頁面。
常見的錯誤用法
這四種都會造成損失
| 錯誤 | 後果 |
|---|---|
全站 canonical 指向首頁 | 等於要求只收錄首頁,其餘全部放棄 |
| 分頁的每一頁都指向第 1 頁 | 第 2 頁以後的內容不會被收錄 |
canonical 指向被 noindex 的頁面 | 訊號矛盾,兩邊都可能不被收錄 |
canonical 指向轉址的網址 | 會被忽略,回到搜尋引擎自己挑 |
分頁那一項特別值得說明:早期有「分頁都指向第一頁」的建議,那已經過時了。分頁的每一頁都該有自我參照的 canonical,第 3 頁的正式版本就是第 3 頁。細節見 分頁與無限滾動的爬取 。
非 HTML 檔案
PDF 這類檔案沒有 <head> 可以放標籤,改用 HTTP 回應標頭:
Link: <https://example.com/whitepaper>; rel="canonical"這和 X-Robots-Tag 是同一類做法,標記放不進去時就往標頭走。
跨網域正規化
同一份內容同時發佈在多個站點(例如:內容轉載)時,canonical 可以指向其他網域:
<!-- 在轉載的站點上,指向原始出處 -->
<link rel="canonical" href="https://original-site.com/article">目標必須真的有同樣的內容
指向一個內容不同的網址會被直接忽略。跨網域正規化的前提是「這兩個網址的內容實質相同」。
檢查清單
| 項目 | 標準 |
|---|---|
每頁都有 canonical | 建議 |
| 是絕對網址 | 建議 |
| 指向自己(除刻意合併的情況) | 必備 |
| 一頁只有一個 | 必備 |
| 目標回傳 200 且非轉址 | 必備 |
| 由框架自動產生而非手寫 | 建議 |
sitemap 只列 canonical 指向的網址 | 必備 |
| 站內連結指向正式版本 | 建議 |
| Search Console 的兩欄一致 | 建議 |
常見問題
重複內容會被搜尋引擎處罰嗎?
不會被處罰,但會造成損失。搜尋引擎會自己挑一個版本收錄,其餘視為重複而忽略。問題是它挑的可能不是您想要的那一個,而且多個版本會分散彼此累積的權重。只有刻意大量抄襲或自動產生的內容才涉及違規。
每一頁都要寫 canonical 嗎?
建議每一頁都寫,而且指向自己。這叫自我參照,它明確告訴搜尋引擎這一頁就是正式版本,也能防止帶追蹤參數的網址被當成獨立頁面收錄。成本極低而效益明確。
canonical 和 301 轉址該用哪一個?
如果使用者不需要看到舊網址,用 301 轉址 ,它更明確也更有效。如果兩個網址都必須能正常開啟,例如:商品同時掛在兩個分類下,才用 canonical。轉址是命令,canonical 只是提示。
為什麼搜尋引擎沒有採用我指定的 canonical?
因為它是提示而不是命令。當內部連結、網站地圖或其他訊號都指向另一個網址時,搜尋引擎可能認為您指定錯了。要讓它被採納,所有訊號必須一致:內部連結、網站地圖 與正規網址都指向同一個版本。
canonical 可以指向其他網域嗎?
可以,這叫跨網域正規化,常用在內容轉載或同一份內容同時發佈在多個站點的情況。要注意指向的目標必須真的有同樣的內容,否則搜尋引擎會忽略這個宣告。
延伸閱讀
參考資料:Google 搜尋中心:指定正規網址