如果 URL 路径或參數里带了中文、空格、逗号,甚至表情符号,那么同一串文字其實存在两種形態:一種是人在地址栏里看到的样子,一種是机器實际传輸的样子。它們在浏览器里看着差不多,在服務器日誌、抓取记錄和索引里却可能不是同一個東西。先把這一点弄清楚,比急着加内鏈更實在。
编碼不是可選装饰,而是實际传輸的形態
HTTP 請求行和响應头里出現非 ASCII 字符时,浏览器和抓取工具會先把它轉成百分号编碼再發出去。比如“搜尋”两個字,會被寫成 %E6%90%9C%E7%B4%A2 這样的形式。服務器收到的是编碼後的路径,後端框架再把它還原成中文字符串。也就是说,從抓取工具到服務器這一段,中文其實並不存在,存在的是一串百分号加十六進制。
問题不在于编碼本身,而在于同一個頁面的 URL 可能因為编碼形式不同而出現多個版本。常见的差异包括:
- 百分号後面十六進制字母的大寫與小寫不一致,例如 %E6 和 %e6,部分服務器會把它們当成不同路径。
- 站内一部分連結直接寫中文,另一部分寫预先编碼好的形式,两種寫法並存。
- 空格被编碼成 %20,還是被寫成加号,两種形式在查询參數里的语义可能並不相同。
- 路径末尾多出一個看不见的空格或換行,肉眼几乎無法分辨。
站内連結统一寫法,比事後合並更省事
導航、分頁、面包屑、正文内鏈里的 URL,最好只保留一種寫法。如果模板輸出的連結是未编碼的中文,而 sitemap 里寫的是编碼後的版本,蜘蛛就會把這两條当成两個入口,各抓一次,最後很可能形成两份副本。與其等它們都進了索引再去處理,不如让模板、sitemap、RSS 和接口返回的連結使用同一套拼接規則。
比較稳妥的做法是路径部分尽量使用英文、拼音或數字,把中文留在标题和正文里;确實需要在參數里携带中文时,统一由程序做一次编碼,不要在模板里手寫百分号,也不要一半编碼、一半不编碼。
几個容易忽略的特殊字符
- & 與 #:前者是參數分隔符,後者是片段标识符,都不會原样發给服務器。想让它們作為内容的一部分,必须先编碼,否則後半截參數會被直接截断。
- ? 與 +:在查询串里有各自的语义,作為值出現时同样需要编碼。
- 末尾斜杠:编碼問题常和斜杠問题叠加在一起,形成四種以上的變体。
- 大小寫:百分号编碼的字母大小寫不统一,是路径去重里最常见的漏網之鱼。
自查顺序
- 先用抓取工具或服務器日誌看一眼蜘蛛實际請求的路径長什么样,而不是凭地址栏里的印象判断。
- 把 sitemap 里的 URL 與頁面内鏈做一次對比,看是否出現编碼與否、大小寫、斜杠不一致的情况。
- 在站内搜一下同一個中文關鍵詞,把可能生成連結的位置都找出来,逐個核對寫法。
- 對確認重复的寫法,選一個保留,其余通過服務端跳轉或替換連結收敛。顺序是先改連結,再谈合並信号。
编碼問题本身通常不會让頁面被拒绝收錄,但它會悄悄把一份内容拆成几份,消耗抓取资源,也让後續的合並判断變得更复杂。
最後提醒一句:不要為了“看起来干净”而频繁改動 URL 编碼規則。已经稳定執行的形式,即便带了百分号,只要能正常响應並被抓取,就不必推倒重来。真正需要處理的,是同一個頁面存在多種寫法,而不是编碼本身。