URL 編碼 / 解碼

線上對 URL 和查詢字串進行百分號編碼與解碼。支援元件、完整 URI、表單三種模式,輸入即時雙向轉換。

把文本轉成 URL 可用的百分號編碼,或還原回來。 在任意一側輸入,另一側會立即更新。請按照值的實際用途選擇模式:單個查詢引數、完整 URL,還是 HTML 表單提交。

把百分號編碼講清楚

URL 為什麼需要編碼

URL 不是自由文本。?#&/= 這些字元是保留字元,它們承擔結構含義:標明路徑在哪裡結束、查詢從哪裡開始、引數之間如何分隔。如果你要傳輸的值本身含有這些字元,接收端的解析器就會誤讀整條 URL。百分號編碼的做法是把這個位元組替換成 % 加上兩位十六進位制值,於是值裡的 &%26 的形式傳輸,絕不會被當成分隔符。

未保留、保留,以及其他

RFC 3986 把字元空間分成三類。

  • 未保留字元A-Z a-z 0-9 - . _ ~。這些永遠不需要編碼,也不該編碼。強行編碼雖然合法,但會讓 URL 更難看,還可能破壞簡單的字串比較。
  • 保留字元: / ? # [ ] @ ! $ & ' ( ) * + , ; =。只有在充當結構分隔符時才可以保持原樣,出現在值裡面就必須編碼。
  • 其餘字元 — 空格、控制字元,以及所有非 ASCII 文本,一律需要編碼。

非 ASCII 與 UTF-8

百分號編碼作用於位元組而非字元,所以要先把文本轉成位元組。現代答案永遠是 UTF-8。 在 UTF-8 裡是三個位元組(E2 82 AC),因此編碼結果是 %E2%82%AC。早期系統有時按頁面自身的字元集編碼,這就是你偶爾還會遇到 Latin-1 或 GBK 編碼亂碼 URL 的原因。本工具全程使用 UTF-8,與瀏覽器和當前所有服務端框架的預期一致。

三種模式,以及各自的誤用場景

encodeURIComponent 是安全預設值,會轉義全部保留字元。只要是把一個值塞進 URL,就用它。encodeURI 刻意保留了保留字元以維持完整 URL 的結構 —— 只應該用來整理已經拼好的整條 URL,絕不要用在單個引數上,因為它會原樣留下值裡的 &,直接毀掉查詢字串。

表單模式是個異類。application/x-www-form-urlencoded 這套序列化方式早於現代 URL 規範,它把空格編碼成 + 而不是 %20。兩種寫法在查詢字串裡都正確,伺服器也都能接受,但如果你在手工構造 POST 請求體,就應當遵循表單約定。

+ 的歧義

正因為表單編碼賦予了 + 特殊含義,表單值裡的字面加號必須自己編碼成 %2B。這是現實中最常見的編碼 bug:一段 base64 字串或一個國際格式電話號碼被原樣傳遞,接收端把每個 + 都變成了空格。如果你的資料可能含加號,要麼顯式編碼,要麼別用表單模式。

雙重編碼

對已經編碼過的字串再編碼一次,每個 % 都會變成 %25,於是 %20 變成 %2520。這通常是 bug —— 往往是應用程式碼編碼了一次,框架或代理又編碼了一次。如果你在 URL 裡看到並非本意的 %25,那多半就是雙重編碼。解碼兩次可以還原,但真正的修復是去掉其中一層編碼。

開源說明:使用標準 JavaScript 的 encodeURIComponentencodeURIdecodeURIComponentdecodeURI 實現,未使用第三方庫。

常見問題

空格該用 %20 還是 +?
查詢字串裡兩者都可以。如果你想要一種到處都合法的寫法,用 %20,因為在路徑片段裡 + 表示字面加號。只有在生成 application/x-www-form-urlencoded 資料時才用 +。
為什麼我的加號變成了空格?
鏈路上有環節把這個值當作表單資料解析了,而表單編碼裡 + 就代表空格。傳送前把字面加號編碼成 %2B 即可。
斜槓需要編碼嗎?
只有當斜槓是值的一部分、而不是路徑分隔符時才需要。含斜槓的檔名必須寫成 %2F,否則伺服器會把它當成多了一層目錄。注意有些伺服器出於目錄穿越防護,預設會拒絕路徑中的 %2F。
編碼區分大小寫嗎?
十六進位制位大小寫都可以,解碼結果完全一致,但 RFC 3986 建議優先使用大寫。%2F 和 %2f 是同一個字元,%2F 是規範寫法。
為什麼我的字串解碼失敗?
百分號後面必須恰好跟兩位十六進位制數字。單獨一個 % 或者 %zz 這樣的寫法是非法的,解碼器會拋錯。如果你的文本里確實有百分號,它本應被編碼成 %25。
資料會被上傳嗎?
不會。編碼和解碼都在你的瀏覽器裡用內建 URI 函式完成,不上傳任何內容。