cv.cm

知識 · 文字、資料與資安

URL 編碼是什麼?

閱讀約 5 分鐘

簡答

URL 編碼正式名稱為百分比編碼(percent-encoding),會把 URL 中不允許或具特殊意義的字元,以每個位元組 % 加兩位十六進位數字的形式取代。空格變成 %20,& 變成 %26,非 ASCII 文字則先轉成 UTF-8,所以「é」會變成 %C3%A9。字串「a b&c」編碼後是 a%20b%26c。

開啟URL 編碼

為什麼 URL 需要編碼

RFC 3986 把 URL 限制在一小組 ASCII 字元內,其中有些字元還有特定任務:? 開始查詢字串,& 分隔參數,= 分開名稱與值,# 開始片段,/ 分隔路徑段落。如果某個值含有這些字元,URL 就會產生歧義。

以搜尋「salt & pepper」為例。直接寫成 ?q=salt & pepper,伺服器會看到參數 q 的值是 salt ,外加另一個名為 pepper 的空參數。編碼成 ?q=salt%20%26%20pepper 後,才會以單一值送達。

哪些字元需要編碼

類別字元規則
非保留字元A–Z a–z 0–9 - . _ ~永遠不需編碼
保留字元(gen-delims): / ? # [ ] @出現在值裡時要編碼
保留字元(sub-delims)! $ & ' ( ) * + , ; =出現在值裡時要編碼
其他所有字元空格、"、<、>、%、非 ASCII一律編碼

編碼是以位元組為單位,而不是字元。非 ASCII 文字會先轉成 UTF-8,每個位元組各自變成一組 %XX:

輸入UTF-8 位元組編碼結果
空格20%20
&26%26
%25%25
éC3 A9%C3%A9
日本E6 97 A5 E6 9C AC%E6%97%A5%E6%9C%AC

十六進位數字不分大小寫,%c3%a9 和 %C3%A9 意思相同,但 RFC 3986 建議統一用大寫。

%20 還是 +:空格的兩套規則

依 RFC 3986 定義的百分比編碼,空格一律寫成 %20。HTML 表單送出時使用另一種相關格式 application/x-www-form-urlencoded,其中空格變成 +,真正的加號則變成 %2B。

  • 在 /files/my report.pdf 這類路徑中請用 %20。路徑中的 + 就是字面上的加號。
  • 在查詢字串中,解析表單編碼的伺服器會把 + 當成空格。%20 兩種慣例都看得懂,不確定時用它比較保險。
  • 如果值裡可能有真正的 +,例如 +84 這種電話號碼,就必須以 %2B 送出,否則會變成空格。

JavaScript 的 encodeURIComponent 與 encodeURI

函式不編碼的字元用途
encodeURIComponent()A–Z a–z 0–9 - _ . ! ~ * ' ( )單一值:一個查詢參數或一個路徑段落
encodeURI()上述字元加上 ; , / ? : @ & = + $ #已經有完整結構的整個 URL
URLSearchParams表單編碼規則(空格變成 +)建立或讀取查詢字串

encodeURIComponent("a b&c") 會回傳 a%20b%26c,而 encodeURI("a b&c") 回傳 a%20b&c,因為它假設 & 是分隔符號。常見的錯誤是對參數值呼叫 encodeURI,讓 &、= 和 # 原樣通過,把值切斷了。

new URLSearchParams({ q: "a b&c" }).toString() 會得到 q=a+b%26c。在標準伺服器上,兩種形式解碼後都是同一個值。

常見錯誤

  1. 重複編碼:對已編碼的文字再編碼一次,%20 會變成 %2520,因為 % 本身被編碼成 %25。每個值只在放進 URL 的那一刻編碼一次。
  2. 用元件函式編碼整個 URL:https:// 會變成 https%3A%2F%2F,連結就失效了。
  3. 路由前先解碼:伺服器若在比對路由前就把 %2F 解成 /,可能被誘導去讀取另一個路徑。
  4. 預設使用舊字元集:有些舊系統把「é」編碼成 %E9(Latin-1)。現代瀏覽器和 WHATWG URL Standard 都使用 UTF-8。

常見問題

為什麼 URL 中的空格是 %20?

URL 中不允許空格,所以用 % 加上它的十六進位位元組值取代。空格的 ASCII 碼十進位是 32,十六進位就是 20。

URL 中的 %2F 是什麼意思?

%2F 是編碼後的斜線,讓 / 能出現在值裡,而不會被當成路徑分隔符號。

URL 編碼和 Base64 一樣嗎?

不一樣。URL 編碼只取代不安全的字元,其餘仍可閱讀。Base64 則把所有位元組轉成 64 個字元的字母表,而且標準版的 + 和 / 本身也需要 URL 編碼,除非使用 URL 安全版本。

帶重音的字母或中文字需要編碼嗎?

實際送出的請求中需要。瀏覽器會在網址列以可讀形式顯示,但送出的是 UTF-8 百分比編碼形式,例如「日」會送成 %E6%97%A5。

所有知識文章