有關 URL 空白字符(%20 和 +)
最近在測試 JavaScript 與 API 參數時,才重新注意到一個很容易被忽略的小地方:同樣是空白,為什麼有時候會看到 %20,有時候卻是 +?而且如果字串本來就有加號,又要怎麼保證它不會被當成空白?
這個問題看起來很小,但它其實很常影響 query string、表單提交、搜尋參數,甚至 Base64 字串傳輸。這篇就把這件事整理清楚。
先講結論
簡單版可以先記這 3 件事:
%20代表空白,屬於一般 URL percent-encoding 的表達方式。+在application/x-www-form-urlencoded的脈絡裡,也常被解讀成空白。%2B才是字面上的加號+。
例如:
|
|
為什麼會有兩種寫法
這跟「你現在處理的是哪一種編碼規則」有關。
1. 一般 URI / URL percent-encoding
在一般 URL 編碼規則裡,空白通常會被編成 %20。這是比較通用、比較直覺的表示方式。
例如:
|
|
這裡的 %20 就是空白。
2. HTML 表單的 form encoding
如果是 HTML 表單送出,尤其是 application/x-www-form-urlencoded 這種格式,空白常會被轉成 +。這是比較舊、但到現在仍然大量存在的規則。
也就是說,+ 不是在所有 URL 場景都等於空白,而是在特定表單編碼規則中,伺服器通常會把它解讀成空白。
最容易搞錯的地方
路徑 path 跟查詢參數 query string 不要混在一起看
下面兩種情境不能混為一談:
- URL path,例如
/files/my report.pdf - query string,例如
?keyword=my report
在 path 裡,通常要用 %20;如果你直接放 +,很多情況它就只是字面上的加號,不一定會被當成空白。
但在 query string,尤其是走表單編碼時,+ 就可能被解讀為空白。
所以不要只記「加號等於空白」,這樣很容易在錯的地方用錯規則。
JavaScript 實際測試
encodeURI 與 encodeURIComponent
|
|
如果你是自己組 query string,通常比較建議針對參數值用 encodeURIComponent,不要手動字串拼一拼就上。
URLSearchParams
|
|
這裡就很能看出差異:
- 空白被轉成
+ - 加號被轉成
%2B
這其實就是表單式 query string 的典型行為。
Java / 後端也常遇到
像 Java 的 URLEncoder 也很常讓人誤會:
|
|
很多人看到這裡會以為 Java 編錯了,其實不是,它是在做偏向 application/x-www-form-urlencoded 的編碼行為。
如果你預期的是純 URI component 的 %20 形式,就要知道工具的語意是否和你要的情境一致。
常見踩雷情境
1. Base64 或 token 裡有 +
如果一段資料本身含有 +,又沒有正確 encode,送到後端後就可能被當成空白,最後驗證失敗。
這也是為什麼很多 token、簽章或 Base64 值放進 URL 時,一定要先 encode。
2. 前端手動拼 query string
像這樣:
|
|
如果 keyword 有空白、加號、&、=,就很容易出事。這種場景應該優先用 URLSearchParams 或至少 encodeURIComponent。
3. 後端框架已經幫你 decode 過一次
有些框架在拿到參數時就已經幫你把 + 還原成空白,這時你再手動 decode 一次,反而可能把資料處理壞。
我自己的判斷方式
如果是一般 URL component,我腦中先預設空白應該是 %20。
如果看到 +,我會先懷疑目前處理的是:
- HTML form submission
application/x-www-form-urlencoded- 某個工具或函式庫幫我用 form 規則編碼
而如果資料裡本來就需要保留加號,那我會特別確認它是不是被轉成 %2B。
小結
%20 和 + 雖然都常代表空白,但它們來自不同脈絡:
%20比較接近通用 URL percent-encoding。+比較常見於表單編碼與 query string 處理。
真正容易出 bug 的不是「不知道有這兩種寫法」,而是沒有分清楚 path、 query string、表單提交、 token 傳遞這些場景的規則差異。
參考資料: