JavaScript 中的 URL 參數解碼,意思是將百分號編碼 (percent-encoding) 反轉,讓像 search?q=hello%20world 這樣的字串可以還原回 hello world。瀏覽器以及任何接收請求的伺服器,在 URL 中只能看到一組受限的字元集,所以空格、帶有變音符號的字母、表情符號,以及 &、=、? 等保留字元,在實際傳送上線之前,都會被替換成一個百分號加上兩個十六進位數字。JavaScript 內建了兩個函式,decodeURIComponent 與 decodeURI,可以處理這個反轉動作,而且它們幾乎能正確處理你會遇到的所有格式正確的值。問題在於靜默失敗:一個孤立的百分號,或一段被截斷的多位元組序列,可能會回傳一個損壞的字串,或根據引擎的不同而拋出 URIError,開發人員常常浪費好幾個小時,只為了把一個壞掉的連結追蹤到某一個錯誤的百分號群組。一個專門打造的 URL Decoder,骨子裡使用同樣的 JavaScript 邏輯,但會在格式錯誤的位置顯示清楚的錯誤訊息,而不是回傳垃圾結果。這就是一行小腳本,和一個專門為檢查、驗證百分號編碼資料而打造的工具之間,實際上的差別。

how to decode url parameters in javascript
How to Decode URL Parameters in JavaScript

URL 參數是如何變成百分號編碼的

每一個 URL 都是由一組很小的可用字元集所組成:字母、數字,以及少數標點符號。完整的清單,包含冒號、斜線、問號、井號、& 與 = 等保留字元,在 RFC 3986 中有定義,它是規範 URI 語法的網際網路標準。任何不在這個字元集內的字元,都必須先進行跳脫,才能安全地在查詢字串、路徑片段或 fragment 中傳送。

百分號編碼的跳脫方式是:把一個字元的每個位元組,替換成一個百分號加上兩個十六進位數字。字母 A 會編碼成 %41,空格會編碼成 %20,而一個中文字或一個表情符號——在 UTF-8 中是多個位元組——會編碼成更長的一連串百分號群組。因為編碼是作用在 UTF-8 位元組序列上,而不是直接作用在 JavaScript 字元上,所以多位元組文字來回轉換時不會損壞。

你可以在最近複製過的任何一個連結上看到結果。一個 Google 搜尋 URL 會包含像 q=how%20to%20decode%20a%20url 這樣的字串,其中查詢值裡的每個空格都已經變成了 %20。一個產品頁的分享連結,常常帶有像 utm_source=newsletter 這樣的追蹤參數,其中又藏了更深一層的百分號編碼資料,而 OAuth 的重新導向 URL,則經常會把整個編碼過的網址塞在單一查詢值裡。

解碼時 JavaScript 實際上做了什麼

JavaScript 提供兩個函式來處理反方向。decodeURIComponent 反轉 encodeURIComponent,會解碼所有看起來像百分號群組的內容,包括解碼後是保留字元的群組。decodeURI 是較保守的兄弟版本:它保留整個 URL 的結構,只會解碼那些不屬於 URL 文法的字元。MDN 對於 encodeURIComponent 的參考文件,詳細記載了兩個函式遵循的精確規則,包括它們不會跳脫哪些標點符號。

實務上,當你想讀取查詢值中對人類友善的文字時,decodeURIComponent 幾乎總是正確的選擇。它預期接收格式正確的 UTF-8 百分號群組,遇到任何其他東西就會拋出 URIError。這個拋出在發生時是很有幫助的——你的程式碼會在送出錯誤資料之前先停住——但它不會告訴你是哪一個百分號群組錯了、為什麼錯了,在一段很長的查詢字串中,單憑肉眼很難定位那一個格式錯誤的序列。

另一件值得知道的事是,這兩個函式骨子裡都是作用在 UTF-8 位元組序列上。這就是為什麼在你的程式碼正確時,CJK 字串或表情符號能夠順利完成來回轉換;也是為什麼當一段序列被一個粗心的日誌轉發器切對半時,結果會變成取代字元或一段不完整的字串。

在解碼之前先讀取 URL 參數

在解碼任何東西之前,你必須先把它取出來。JavaScript 提供兩種乾淨的方法。傳統的方式是讀取 window.location.search,然後自己手動解析或用一小段 regex 處理。現代的方式則是使用 URLSearchParams,它在每個目前的瀏覽器中都有內建,會自動幫你切分鍵與值。常見的寫法像這樣:

const params = new URLSearchParams(window.location.search);const q = params.get('q');

你從 URLSearchParams.get 拿到的字串,在百分號群組層級已經做過解碼了。這很方便,但它繼承了 decodeURIComponent 相同的邊界情況:查詢值中一段格式錯誤的百分號序列會拋出例外,而且你仍然必須決定要怎麼處理它。

這就是工具派上用場的時刻。當真實世界的參數拋出例外時,把它複製到 URL Decoder,切換到 Component 模式,然後貼上。錯誤訊息會告訴你精確的位置與精確的問題,接著你就能在來源中修正它,或在你的解析程式碼中加以防範。

四個步驟在 JavaScript 中解碼 URL 參數

  1. 選擇範圍。如果你要解碼的是單一查詢值、路徑片段或 fragment,就選 Component 模式。如果你複製了整個網址,想看到它被整理過但不破壞其結構,就選 Full URL 模式。
  2. 選擇 Decode 作為方向。另一個選項 Encode 則是以相反方向執行轉換。
  3. 把編碼過的文字貼到輸入框。解碼結果會在你輸入或貼上時即時更新。如果輸入格式錯誤——孤立的百分號、%zz,或被截斷的多位元組序列——工具會停下來並顯示清楚的錯誤訊息,而不是產出一個壞掉的字串。
  4. 按 Copy 將可讀的文字放到你的剪貼簿。接著你可以把它貼到 console、組態檔,或你正在除錯的程式碼中。

對於大多數 JavaScript 除錯情境,Component 模式加上 Decode 是正確的組合。像 hello%20world%21 這樣的值,會立刻讀回 hello world!。如果這個值本身是一個編碼過的 URL、藏身於另一個參數之中,請切換到 Full URL 模式以保留外層結構,並把結果當作內層的網址,而不是當作一段單純的文字。

Component 模式 vs Full URL 模式

這兩種模式存在,是因為「URL 編碼」依情境不同代表兩種不同的工作。Component 模式是嚴格的。它會跳脫所有保留字元,包含 &、=、/、?、#,以及少數額外的字元(驚嘆號、撇號、括號、星號),這些字元在某些伺服器與簽章機制中會被特別處理。當你要建立一個不能與周圍分隔符號相衝的查詢值時,這種嚴格性正好是你想要的。

Full URL 模式則保留結構字元,只跳脫真正不安全的部分,例如空格與非 ASCII 字母。當你手上是一個完整的網址、需要在不喪失其文法的情況下整理乾淨時,請使用它。

字元Component 模式Full URL 模式
空格%20%20
&%26&
=%3D=
?%3F?
#%23#
/%2F/
:%3A:
!%21!
'%27'
(%28(
)%29)
*%2A*

閱讀表格的方式:Component 模式對每一列都會跳脫。Full URL 模式只跳脫空格與任何非 ASCII 字元;保留的標點符號則保持原樣,以維持 URL 文法的完整。

什麼算是格式錯誤的輸入

URL Decoder 拒絕產生損壞的結果。常見的嫌疑犯有三種模式:

  • 孤立的百分號後面什麼都沒有,例如 hello%。
  • 百分號後接非十六進位字元,例如 %zz 或 %2X。
  • 被截斷的多位元組序列,例如 %E4%BD,缺少了某個 UTF-8 字元的第三個位元組。

在每一種情況下,工具都會停下來、高亮顯示該位置,並說明哪裡出錯。如果你把同樣的字串貼進 decodeURIComponent,你會拿到一個沒有指向錯誤群組的 URIError;有了這個工具,你會確切知道要在來源中修正哪一個字元。這就是為什麼在驗證來自第三方 API 或日誌管線的資料時,開發人員會求助於它——因為一個格式錯誤的值,就會讓整批資料靜默地失敗。

反過來用也很有用。如果你在測試一個會回傳編碼資料的服務,而你需要確認它真的能來回轉換,請把編碼後的輸出貼到工具中、解碼,然後再用 Component 模式重新編碼並比較。原輸入與重新編碼後輸出之間的任何飄移,都代表你自己的程式碼裡有雙重編碼的 bug,而這正是你在分享連結中偶爾會看到的 %2520 這類殘留物最常見的來源。

什麼時候瀏覽器工具勝過程式碼片段

JavaScript 的內建函式對於格式正確的輸入既快速又正確。至於其他所有情況,URL Decoder 讓你不必再寫驗證迴圈。這個工具完全在瀏覽器中執行,所以你貼上的百分號編碼字串——包含權杖、內部 URL、客戶資料——永遠不會離開你的機器。沒有上傳步驟、沒有帳號,也沒有伺服器會看到你的輸入。即使頁面已經載入完成,它仍然可以繼續運作,這在你用不穩定的連線或在企業代理伺服器後除錯時特別重要。

更大的勝利在於回饋。對解碼後的值做 console.log 只會告訴你結果是錯的;這個工具會告訴你是哪裡出錯了。對於一次性解碼,這個差別很小。對於批次驗證、regex 調校,或逆向工程一個陌生的 API,這個差別很快就會累積起來。

如果你是在較大的工作流程中用 JavaScript 進行解碼——例如,建立一個搜尋框,讀取它的查詢參數並顯示出來——請繼續在程式碼中使用 decodeURIComponent,並在你需要檢查或驗證時求助於這個工具。兩種做法並不互相衝突;這個工具是驗證步驟,用來捕捉你的程式碼也應該處理的邊界情況。想看另一種語言搭配同一個工具的平行說明,請參考 Decode URL Strings in Java: Code and a Browser Tool

如果你正在權衡各種選項,Base58 Decode for Beginners: A Byte-First Workflow 對此有詳細介紹。