在 Java 中,百分比編碼的 URL 只要一個呼叫就能解碼:URLDecoder.decode(percentEncodedString, StandardCharsets.UTF_8),它位於 java.net 套件中,會將每個 %XX 序列轉回原本的 UTF-8 字元。兩個參數都很重要:一個是存放百分比群組的輸入字串,另一個是明確指定的字元集,幾乎都是 UTF-8,這樣表情符號、變音字母以及 CJK 文字才能在來回轉換中存活下來。較舊的程式碼若沒有傳入字元集,會依賴平台預設值,當伺服器與用戶端的預設值不一致時,任何超出 ASCII 的內容都會在不知不覺中被損壞。較新版的 URLDecoder.decode(String, Charset) 多載會將編碼納入合約的一部分,因此解碼行為在任何機器上都會一致。然而,如果目的只是為了除錯時讀取一個百分比編碼的連結、把值複製到 API 請求中,或是檢查 OAuth 回呼參數的實際內容,就不必寫那段用完即丟的程式碼——一個瀏覽器版的 URL 解碼工具在網頁中執行完全相同的 UTF-8 來回轉換,還附帶複製到剪貼簿的功能,以及當輸入格式錯誤時顯示清楚的錯誤訊息。

在 Java 程式裡,URL 解碼究竟代表什麼
URL 解碼是百分比編碼的反向過程——百分比編碼會把網址中不安全的字元替換成一個百分比符號加上兩個十六進位數字。字串 Hello%20World%21 在解碼後會變成 Hello World!,而像 %E4%BD%A0%E5%A5%BD 這樣的中文問候語,在將百分比群組讀為 UTF-8 位元組後,會變成 你好 這兩個字。RFC 3986 明確定義了哪些字元在 URL 中是保留字、哪些必須跳脫,該文件是 Java 標準函式庫以及你可能用到的任何第三方解碼器的權威參考依據。
Java 把編碼後的文字表示成一般的 String——核心函式庫裡並沒有特殊的 URL 型別——而解碼過程是一種字串到字串的轉換。這就是為什麼必須傳入字元集:String 內部其實已經是 Unicode,但產生它的位元組在進入時是用某種編碼解讀的,你必須告訴解碼器在將百分比序列重新組合成字元時該使用哪一種編碼。
解碼百分比編碼 URL 的精確 Java 程式碼
可運行的最短程式片段只要三行。第一行是輸入,第二行執行解碼,第三行是結果。
| 步驟 | 程式碼 |
|---|---|
| 1. 定義編碼後的輸入 | String encoded = "Hello%20World%21%F0%9F%91%8B"; |
| 2. 使用 UTF-8 解碼 | String decoded = URLDecoder.decode(encoded, StandardCharsets.UTF_8); |
| 3. 結果 | // decoded == "Hello World! 👋" |
第三行展示了來回轉換的結果:一個空格、一個驚嘆號,以及一個四位元組的表情符號,全都完整還原。新版的雙參數 URLDecoder.decode 接受一個 Charset 物件,完全消除了究竟使用哪種編碼的模糊空間。如果你使用的是 Java 10 之前的程式碼,較舊的單參數形式 URLDecoder.decode(String) 仍然存在,但已被棄用,原因正是它會退回到平台預設字元集,而這在伺服器上很少是你想要的結果。
如果要處理整個 URL 字串而非單一值,也可以用同樣方式對整段進行解碼。
| 步驟 | 程式碼 |
|---|---|
| 1. 定義編碼後的 URL | String fullUrl = "https%3A%2F%2Fexample.com%2Fsearch%3Fq%3Djava%20url%20decode"; |
| 2. 使用 UTF-8 解碼 | String readable = URLDecoder.decode(fullUrl, StandardCharsets.UTF_8); |
| 3. 結果 | // readable == "https://example.com/search?q=java url decode" |
可以看到 %3A 變成 :,%2F 變成 /,而 %3F 變成 ?。解碼器並不會去理解或在意結果看起來像一個 URL——它只是把百分比群組轉成字元。如果你把 URL 的結構字元也解碼,就會失去讓程式把結果當作網址解析的能力;這是「元件模式」與「完整 URL 模式」之分存在的其中一個原因。
什麼時候瀏覽器工具能讓你免於寫 Java 程式
就算只是一行程式碼的解碼,寫 Java 也是有成本的。你需要 JDK、一個專案、一個主類別、一個建置步驟,以及 IDE 或至少一個終端機。如果你只是想讀取別人在聊天中貼出的百分比編碼連結、解碼 OAuth 回呼值來看它真正的內容,或是確認查詢字串中的百分比群組與原始搜尋詞一致,這些額外負擔都不值得。一個在瀏覽器中用 JavaScript 執行同樣 UTF-8 解碼的工具,讓你貼上字串就能立刻得到答案。
這個 URL 解碼器 完全在瀏覽器中執行,這代表百分比編碼的權杖、帶有內嵌密鑰的回呼 URL,以及內部連結,都不會離開你的裝置。沒有上傳、不需要帳號、不會有伺服器端的輸入記錄,而且頁面載入完成後仍可繼續運作,讓你離線時也能使用。它也會誠實地顯示錯誤:孤立的百分比符號或不完整的多位元組序列會產生清楚的提示,而不是一段損壞的字串,這與 Java 解碼方法在拋出 IllegalArgumentException 時的行為一致。
如何在瀏覽器中使用 URL 解碼器來解碼 URL
- 在瀏覽器中開啟 URL 解碼器頁面。
- 選擇範圍。當輸入是單一查詢值、路徑區段或片段時,選擇「URL 元件」,所有保留字元都會被正確處理。當輸入是完整的網址,你想保留其結構(冒號、斜線、問號、井號),只讓真正不安全的字元被跳脫或還原時,選擇「完整 URL」。
- 選擇方向。若要解碼,請選「解碼」,讓工具反向執行百分比編碼,而不是套用它。
- 把百分比編碼的文字貼進輸入框。輸出會在你輸入時即時更新,因此你可以看到每個百分比群組在被辨識出來的瞬間,立刻還原成原本的字元。
- 如果輸入格式錯誤——例如單獨的 %、百分比符號後接非十六進位字元,或是被截斷的多位元組序列——工具會停止並顯示明確指出問題的錯誤訊息,而不是產生損壞的字串。
- 點擊「複製」,將解碼結果放到剪貼簿,即可貼到編輯器、聊天訊息、API 請求內容,或是 Java 原始碼檔案中。
解碼時的元件模式 vs 完整 URL 模式
這兩種範圍之所以重要,是因為同一段百分比編碼的字串在不同的情境下可能代表不同的意義。「元件」是 URL 中的一個片段,例如一個 q= 值或一個路徑區段;「完整 URL」則是整個網址。下表說明了選擇不同模式會如何改變解碼器的行為。
| 面向 | 元件模式 | 完整 URL 模式 |
|---|---|---|
| 輸入類型 | 單一查詢值、路徑區段或片段 | 一個完整的網址 |
| 保留字元 | 編碼時全部跳脫,解碼時全部還原 | 予以保留(冒號、斜線、?、#) |
| 典型輸入範例 | java%20url%20decode%21 | https%3A%2F%2Fexample.com%2Fpath%3Fa%3D1 |
| 典型輸出範例 | java url decode! | https://example.com/path?a=1 |
| 最佳用途 | 查詢字串或路徑中的單一值 | 清理或讀取整個連結 |
當百分比編碼的文字只是 key=value 中的值、一個路徑區段的內容,或是 # 之後的片段時,請選擇元件模式。當輸入已經具有位址的形式——scheme://host/path?query#fragment——而且你希望保留這個結構時,請選擇完整 URL 模式。對於純粹用 Java 解碼整段 URL 字串,你可以用同樣的方式呼叫 URLDecoder.decode;這個工具只是把選擇明確化並顯示出來。
為什麼解碼錯誤會浮現(以及如何修復)
Java 解碼器在遇到百分比符號後面沒有接兩個十六進位數字時,會拋出 IllegalArgumentException。瀏覽器工具則會以可讀的錯誤訊息呈現相同的結果。常見的原因包括:字串在上游某處被重複編碼、人工編輯連結時刪掉了兩個字元而留下孤立的 %、因緩衝區大小限制而被截斷的 UTF-8 序列,或是某個有缺陷的用戶端引入的非標準十六進位數字如 %zz。修正方式應是回頭檢查產生編碼字串的上游,並重新乾淨地編碼,而不是去修補已解碼的輸出。
根據 RFC 3986,百分比符號後的兩個十六進位數字必須來自 0-9 A-F a-f 這個集合。根據定義,任何落在這個集合之外的內容都屬於格式錯誤。Java 解碼器和瀏覽器工具都會將格式錯誤的輸入視為嚴重失敗,正因如此:回傳一個損壞的字串將會讓毀損的資料流入下游的資料庫、分析管線,或 API 請求中。
Java 程式碼 vs 瀏覽器工具:選擇正確的做法
兩種做法在有效輸入下都會產生相同的正確輸出。決策的重點在於工作應該在哪裡執行。下表整理了實際上的差異。
| 面向 | Java URLDecoder.decode | 瀏覽器 URL 解碼器 |
|---|---|---|
| 執行位置 | 在 JVM 內部,於您的應用程式中 | 在瀏覽器分頁內部,以原生 JavaScript 執行 |
| 所需設定 | JDK、專案、建置、IDE 或終端機 | 開啟頁面 |
| 網路 | 無 — 在本機執行 | 無 — 在頁面載入後於本機執行 |
| 字元集 | 明確指定 Charset 引數(建議使用 UTF-8) | 預設為 UTF-8 |
| 錯誤行為 | 拋出 IllegalArgumentException | 顯示清楚的內聯錯誤訊息 |
| 適用情境 | 正式環境程式碼、自動化的管線、測試 | 除錯、一次性檢查、讀取分享的連結 |
| 資料處理 | 留在 JVM 執行所在的那台機器上 | 留在瀏覽器中,不會上傳任何資料 |
對於處理使用者輸入或 API 回應的應用程式碼,請堅持在 JVM 中使用 java.net.URLDecoder.decode — 這才是工作應該執行的地方。對於臨時的除錯、解碼某人貼在工單中的 URL,或檢查追蹤參數,URL 解碼器工具會比啟動一個 Java 專案來得快,並能得到同樣正確的 UTF-8 結果。
最後一個實用的提醒:在 Java 中解碼時,建議使用兩個引數的 decode(String, Charset) 形式,並明確傳入 StandardCharsets.UTF_8。單引數的形式已被棄用,會使用平台預設字元集,而在伺服器上這個字元集很少是 UTF-8,會悄悄地把非 ASCII 字元弄得一團糟。瀏覽器工具已經做了等效的處理 — 每個百分號編碼群組都會以 UTF-8 解讀 — 因此您無需操心這個問題。encodeURIComponent 與 decodeURIComponent 的 MDN 說明文件描述了底層瀏覽器函式相同的 UTF-8 契約。
若想更深入了解,請參閱 ASCII 碼轉換速查表:快速的十進位參考。
若想更深入了解,請參閱 在 C# 中解碼 Base32:瀏覽器工具或程式庫。