SheepDev

編碼與字元集

正確處理 URL 中的中文、+ 與 %20

使用工具

同一搜尋詞卻丟了空白,或加號變成空白。URL 問題不僅取決於轉了幾次,還取決於文字代表哪一部分。完整 URL 中應保留的分隔符號,放在值裡可能就需要編碼。

用 URL 編碼工具逐一轉換短字串,只檢查表示,不存取 URL;example.invalid 是範例位址。編碼看起來正確,不證明資源存在或連結安全。

比較一個空白的兩種編碼

含空白的輸入
red blue

元件編碼得到 red%20blue,表單模式得到 red+blue。它們屬於不同約定,並非某個總是錯。加號只在套用表單規則的地方代表空白,不是在所有 URL 位置都如此。需確認接收解析規則。

解碼也要選擇對應規則。普通解碼保留 red+blue,把表單加號視為空白才得到 red blue。結果異常時,不要反覆解碼,先確認輸入是普通元件還是表單值。

C++ 的加號不是空白

含加號的輸入
C++ guide
元件/表單結果
C%2B%2B%20guide
C%2B%2B+guide

即使表單模式,原加號也編碼為 %2B,以區別由空白生成的 +。直接把未編碼的 C++ guide 當表單解碼,會把原加號也變空白。必須區分原始與已編碼值。

保留還是轉換 &,取決於角色

作為一個搜尋詞傳送的值
tea & cake

元件編碼為 tea%20%26%20cake。把原 & 接進查詢可能被當作參數分隔符號;反過來把完整 URL 的 ?、& 都當一個值編碼,也會破壞結構。需區分建立 URL 與放入單一值。

完整 URL 模式保留部分結構符號,但不會推測意圖並修復壞 URL。可用 URL 分解檢查主機、路徑、查詢與片段。查詢值中的字面 # 不應意外成為片段起點。

%2520 可能提示多了一層編碼

元件編碼兩次
red blue → red%20blue → red%2520blue

第二次把百分號編碼為 %25,一次解碼後仍有 red%20blue,看似沒解碼。只看值無法判斷是誤編碼兩次,還是本來要傳送字面 %20,應追蹤兩端轉換。

不要解碼到百分號全消失,本來作為文字的 %2F 可能變分隔符號並改變意義。正確層數由資料約定決定,不由外觀決定。調查時區分編碼前、傳送前與解析後值。

為什麼一個日文字會變成多個 % 序列

UTF-8 位元組與 URL 表示
あ
UTF-8: e3 81 82
URL: %E3%81%82

每個百分號後的兩位在此代表一個 UTF-8 位元組。あ 占三位元組,因而三組百分號;不是把碼位 U+3042 寫成 %3042。結合文字位元組轉換,可串起字元、編碼位元組與 URL 表示三層。

截斷的 %E3%81 或非十六進位 %ZZ 無法正確解碼。不要猜補位元組以消除錯誤,應檢查來源值是否截斷。舊系統使用其他編碼時,本解碼器也不能自動確定原字元集。

回到實作時,明確在哪一步編碼

記錄原搜尋詞、選擇規則、編碼值和接收規則。red blue 通過,不代表 C++ guide 或 tea & cake 也正確。保留空白、+、&、#、% 的小例子,可用於 URL 建立變更後的迴歸。

程式中使用結構化 URL 或查詢 API 可減少手工串接,但 API 已編碼值時,不要預先重複編碼。實驗目的不是增加轉換,而是確定由哪一層負責必要轉換。

區分值裡的 & 與查詢分隔符 &

搜尋詞 red & blue 中的 & 屬於值。直接拼接可能被當作新參數邊界。元件編碼為 red%20%26%20blue,表單編碼為 red+%26+blue;兩者都用 %26 保護字面 &,只是空格表示不同。保留查詢分隔符與保護值內字元是兩件事。

排查時並列原值、組成的 URL、接收值。網址列可能美化顯示,不能僅憑外觀認定雙重編碼。用 URL 分解工具檢查參數能否還原 red & blue,無需存取地址。反覆解碼整個 URL 可能把受保護的 %26 變成結構分隔符 &,每次都應明確轉換層。

只有非 ASCII 值失敗時,應先查哪層處理 UTF-8 位元組,不要立即換字元集。百分號後的兩位表示編碼位元組,不是 Unicode 字元編號。編碼變長不等於原字元增加,排查長度限制時應分開測原值與組裝 URL。

參考資料

使用工具

指南 →