爬虫判断“這是不是同一個 URL”,靠的是字符串本身;而服務器判断“這個請求该返回什么”,靠的是文件系統規則、重寫規則和預設文档配置。当這两套口径不一致时,同一個頁面就可能以多種寫法被反复發現,日誌里看起来入口很多,實际内容却只有一份。
差异通常從哪里来
- 服務器或容器镜像對路径大小寫不敏感,/About 與 /about 都可能返回 200,正文完全一样。
- 重寫規則或 try_files 自動补斜杠,/list 直接 301 到 /list/,但内鏈里两種寫法混用。
- 模板不同位置手寫的連結不一致,導航輸出 /Product/,正文里却是 /product。
- 入口同时存在带與不带預設文档名的版本,例如 /a/ 與 /a/index.html。
- CDN 或反向代理做過路径归一化,源站日誌看到的路径與爬虫實际請求的寫法並不完全一致。
會带来什么影响
最直接的结果是抓取請求被分散到若干“看起来不同”的入口上,同一份内容被多次請求;其次是統計失真,你在日誌里數出来的入口數、狀態碼分布,可能並不對應真實頁面數量。如果 sitemap、canonical 和内鏈各用一種寫法,後續做覆盖核對时也會對不上号。
自查顺序
- 先從訪問日誌里取样,把狀態碼為 200 的路径按小寫形式分组,找出同一路径出現多種大小寫寫法的记錄。
- 用 curl 分別請求 /About、/about、/About/,记錄狀態碼、Location 响應头,以及返回正文的長度或 ETag 是否一致。
- 核對 sitemap、feed、内鏈模板中同一路径的寫法是否统一,是否存在两套寫法同时被抓。
- 检查服務器配置中的 rewrite、try_files、DirectorySlash 一類指令,確認是否已经存在归一化規則,規則之間是否互相冲突。
- 對比 canonical、og:url 里指向的形式,與頁面的主要入口寫法是否一致。
收敛處理思路
先選定一種規范形式,常见做法是小寫、静態文件不带结尾斜杠、目錄類保留斜杠,其余寫法统一用 301 收敛過去。只靠 canonical 声明通常不够,因為它不减少爬虫對這几種寫法的實际請求。
- 在服務器层做 301 归一化,比在每個頁面里寫标簽更彻底。
- 内鏈、sitemap、分頁组件同步改成同一形式,避免繼續产生新入口。
- 301 的目标要直接落到最终地址,不要出現跳向另一個 301 的情况,否則會形成鏈條。
- 如果服務端本身区分大小寫,可以直接對错誤寫法返回 404,但改動前要確認没有真實存在的混合大小寫頁面被誤伤。
調整归一化規則之前,先抽一批真實 URL 做回归,尤其是带查询參數、带語言前缀的入口,避免把有效頁面誤重定向掉。
驗證是否收敛
規則上线後,隔一段時間再按同样的方式抽样日誌:看同一路径的小寫分组里是否只剩一種寫法,301 的命中量是否在下降並趋于稳定,sitemap 中被抓取的 URL 是否與内鏈輸出形式一致。這個過程不需要大改,重点是持續抽样核對,比一次性全站替換更容易發現遗漏。