先分清:差异是“字符串差异”還是“资源差异”
URL 本质上是一串字符,但判断它是不是同一個頁面,看的不只是字符串,還要看服務器怎么响應。同一份 HTML,如果两個地址都返回 200,且内容一致,索引里就有可能出現两版;如果其中一個 301 到另一個,通常只會保留目标地址。
所以處理這類問题,第一步不是急着寫 canonical,而是先看服務器對几個變体分別返回什么。
三類常见的 URL 變体
1. 大小寫
在 Linux 环境下,路径部分通常区分大小寫,/About 和 /about 很可能被当成两個不同地址,各自返回 200。而在一些 Windows 环境或部分框架路由下,两者指向同一頁面,但返回的仍是 200 而非重定向。前者容易产生两份副本,後者容易出現“两個地址、同一内容”的情况。
域名部分不区分大小寫,這一块基本不用担心。
2. 结尾斜杠
/news 和 /news/ 是否等價,取决于服務器配置。有的服務器會自動 301 到带斜杠的版本,有的則两者都能正常打開。如果两者都返回 200,就形成了两個可訪問地址。
這類問题常出現在目錄頁和列表頁上。检查方法很简單:分別訪問两個地址,看返回碼和最终 URL。
3. 追踪參數與排序參數
?from=wechat、?utm_source=xxx、?sort=price 這類參數,如果服務器不做處理,會生成大量只差參數的地址。它們往往内容相同或高度相似,却各自能被訪問、被連結、被抓取。
真正需要保留的,是那些會改變頁面内容的參數,比如分頁、篩選、排序。纯粹用于統計来源的參數,一般没有必要让它們生成獨立頁面。
優先用哪几種方式收口
- 服務器层重定向:把不想要的變体 301 到規范地址。這是最干净的做法,因為它在抓取阶段就把两個地址合並成一個。
- canonical 声明:無法做重定向时,用 canonical 指向規范版本。它属于提示,不保證一定被采纳。
- 站内連結统一:内鏈、導航、站点地图里都用同一個版本的地址。連結本身就在不断强化哪個是主版本。
- robots.txt 或參數處理工具:對于纯追踪類參數,可以在工具里声明忽略,或在 robots.txt 里挡掉特定參數组合。注意這挡的是抓取,不是收錄,已经收錄的地址不會因此消失。
一個常见的誤区:以為加了 canonical 就萬事大吉。如果站内到處連結的都是另一個版本,canonical 的作用會被明顯削弱。
怎么驗證處理是否生效
- 用不带缓存的請求分別訪問各個變体,记錄返回碼和跳轉鏈。
- 在服務器日誌里看這几個地址的抓取情况,观察是否還有大量重复抓取。
- 過一段時間看索引覆盖,確認重复地址是否在减少。這個過程通常需要几周,不會立刻见效。
几個容易忽略的细节
第一,跳轉鏈不要超過一跳。A 跳 B、B 跳 C 會延長處理時間,也容易在中間环节丢失信号。
第二,不要用 JavaScript 做归一。抓取阶段拿到的往往是不执行脚本的 HTML,指望前端跳轉来合並地址,很多情况下不會生效。
第三,已经收錄的地址不用急着删。做好重定向後,索引會随着重新抓取慢慢更新。急着返回 404,反而可能让用戶和爬虫都收到错誤信号。
第四,規范地址本身要稳定。如果規范版本响應慢、经常报错,那這套归一就没有意义。
總结一句:URL 归一不是為了“看起来整齐”,而是為了让同一份内容只有一個入口,让抓取和索引的位置都集中在一個地址上。先看服務器怎么响應,再决定用重定向還是 canonical,最後用日誌和索引报告驗證结果。