URL Parser 是一個以瀏覽器為基礎的檢視工具,會用 WHATWG URL 標準,把一個絕對的 HTTP 或 HTTPS 網址,拆解成通訊協定、來源、主機、主機名稱、連接埠、路徑名稱、查詢字串、雜湊值、檔案名稱,以及依序排列的查詢參數。對於搜尋 Java 解法時來到這個頁面的開發者,實際情況是,你根本不需要 JVM、建置腳本,或 java.net.URL 匯入,才能檢視一個連結裡裝了什麼——現代瀏覽器內部執行的正是同一套 WHATWG 剖析器,而它透過一個小型的用戶端介面公開出來,整個過程都在你目前的分頁中執行。貼上連結、點擊剖析,這個工具就會回傳正規化後的 href、來源,以及每一個獨立的組成部分,連同一個依序排列的查詢參數陣列。這個網址永遠不會被上傳,這個請求永遠不會被送往你貼上的那個位址,結果也不會有任何部分被靜默截斷或取樣。這讓這個工具,成為你想除錯一個應用程式連結、稽核重複的參數,或了解一個預設連接埠或國際化主機名稱如何序列化時,一個快速的第一站,不必編譯任何一行 Java 或其他伺服器端程式碼。

how to parse url in java
how to parse url in java

URL Parser 對一個 HTTP 網址會回傳什麼

URL Parser 會把一個絕對的 HTTP 或 HTTPS 網址,拆解成大多數開發者在除錯連結時會用到的十一個欄位。這個工具直接從瀏覽器的 URL 物件中,讀取通訊協定、主機名稱、連接埠、主機、來源、路徑名稱、檔案名稱、查詢字串、雜湊值,以及完整的 href,再用 URLSearchParams,把查詢字串列舉成一個依序排列的查詢參數陣列。這些欄位沒有一個是從網路請求推導出來的,因此結果精確反映了 WHATWG URL 剖析器在這台裝置上,如何序列化你的輸入內容。你可以try URL Parser in a fresh tab,並拿一個你已經知道答案的連結,對照輸出結果確認。

欄位來源於 URL 物件的哪個屬性針對 https://shop.example.com:8443/cart/index.html?ref=summer&ref=fall#coupon 的範例值
protocolURL.protocolhttps:
hostnameURL.hostnameshop.example.com
portURL.port8443
hostURL.hostshop.example.com:8443
originURL.originhttps://shop.example.com:8443
pathnameURL.pathname/cart/index.html
filename序列化後路徑的最後一段index.html
searchURL.search?ref=summer&ref=fall
hashURL.hash#coupon
queryParamsURLSearchParams entries[{name:"ref",value:"summer"},{name:"ref",value:"fall"}]

重複出現的 ref 參數,會依原樣完整保留。URL Parser 不會把它們合併成一個物件,因此你可以看出一條分析或 A/B 測試管線,是否送出了同一個鍵兩次、順序如何,以及各自的值是什麼。這與在 Java 中用一個粗略的 String.split("&") 做法,或用一個會不動聲色覆寫重複值的正規表示式擷取器相比,是一個雖小卻重要的差異。

瀏覽器檢視工具在什麼時候勝過 java.net.URL

在 Java 中,java.net.URL 的設計目的,是為了處理通訊協定與開啟連線,而不是靜態檢視。要從一個字串中擷取通訊協定、主機、連接埠、路徑、查詢字串與片段,你通常得先實例化這個 URL,再呼叫 getProtocol()、getHost()、getPort()、getPath()、getQuery() 與 getRef(),然後手動用 & 把查詢字串切開。這個做法能編譯、能執行、也能回答你的問題——但同時也拉進了一個 JVM、你的建置系統,以及幾分鐘的往返時間,而你真正想要的,只是讀懂這個連結裡有什麼。一個以瀏覽器為基礎的網址檢視工具,把MDN URL documentation所描述的那套 WHATWG URL 標準,變成了一個可以點擊的介面。結果是一個正規化後的 href,加上每一個獨立的組成部分,呈現方式與真實瀏覽器解讀這個連結的方式完全相同,而且從不真正開啟它。

三個步驟剖析一個網址

這個工作流程刻意設計得很短。每個步驟都只在目前的作用中分頁進行,因此不會有任何東西離開你的機器,而且每次重新執行,剖析器都會從一個清空的狀態重新開始。

  1. 把一個絕對的 HTTP 或 HTTPS 網址,貼進輸入框中。這個網址必須獨立識別出自己的協定與主機——路徑、與協定相對的參照,以及裸露的網域,都會被拒絕,而不是對照目前頁面解析。含有非空使用者名稱或密碼的網址,同樣會在這個階段被拒絕,好讓憑證永遠不會進入輸出結果。輸入框下方的字元計數,是即時計算的 UTF-16 碼元長度,最多恰好接受 8,192 個。
  2. 選擇Parse URL。這個工具會在不提供基底網址的情況下建構這個 URL,要求正規化後的通訊協定必須是 http: 或 https:,並拒絕任何其他協定(包括 javascript:、data:、file:、ftp:、blob: 與 mailto:)。結果面板接著會顯示正規化後的 href、origin、protocol、host、hostname、port、pathname、search、hash、filename,以及依序排列、已解碼的查詢參數。
  3. 檢視查詢字串與雜湊值中是否含有敏感資料,如果你想分享或儲存,就把完整剖析後的 JSON 複製到剪貼簿。編輯輸入內容,會立即清除先前的結果、錯誤訊息、查詢清單、摘要與剪貼簿狀態,因此一次失敗的網址,絕不會讓先前成功的結果殘留在畫面上。

如果剪貼簿權限被拒絕,完整的 JSON 仍然可以手動選取——沒有任何欄位被隱藏或壓縮。如果你需要再次檢視同一個網址,直接貼上並重新執行即可;先前的 JSON 不會被快取在目前工作階段之外的任何地方。

每個組成部分是如何被正規化的

WHATWG URL 剖析,並不是逐字直接透傳。你輸入內容中的幾種字元,會被靜默正規化,好讓結果反映瀏覽器實際會在網路上送出的內容。下表整理了 URL Parser 呈現出來的規則,每一條都直接取自 MDN URL 參考文件。

原始細節正規化後的行為具體範例
大寫的通訊協定轉為小寫HTTPS://Example.COM → protocol 為 "https:",主機也轉為小寫
預設 HTTPS 連接埠 443從 host 與 port 中移除https://example.com:443/ → port 為 "",host 為 "example.com"
非預設連接埠同時保留在 host 與 port 中https://example.com:8080/ → port 為 "8080",host 為 "example.com:8080"
國際化主機名稱轉換成 ASCII(Punycode)https://例え.jp/ → hostname 為 "xn--r8jz45g.jp"
空的路徑名稱變成單一斜線https://example.com → pathname 為 "/"
以斜線結尾的路徑名稱檔案名稱為空https://example.com/docs/ → filename 為 ""
路徑中的百分比編碼位元組原樣保留/docs/page%20one → pathname 為 "/docs/page%20one"
帶中括號的 IPv6 主機保留中括號,附加連接埠http://[2001:db8::1]:8080/ → host 為 "[2001:db8::1]:8080"

其中有兩條規則特別容易被忽略。hostname 欄位顯示的是瀏覽器 URL API 正規化後的 ASCII 序列化結果,這對於比對瀏覽器實際會序列化成什麼很有用。它不是 DNS 查詢結果、網域信譽結果、註冊查詢結果、擁有權證明,也不是同形異義字警示。以斜線結尾的規則,也是許多自行手刻的 Java 剖析器容易出錯的地方,因為它們往往退回用 substring(lastIndexOf('/')) 這種寫法,並靜默回報字面上的空字串做為檔案名稱——這正是 URL Parser 回報的結果,只不過它是對正規化序列化後的路徑名稱做同樣的事,而不是對你的原始文字。

硬性限制與憑證規則

URL Parser 是一個檢視工具,不是一個抓取工具。它從不導向你貼上的網址、從不送出請求,也從不接收重新導向、DNS 回覆、TLS 憑證,或 Content-Disposition 標頭。以下這些邊界都明確訂定,好讓這個工具不會被不知不覺地誤用成連結驗證器或惡意連結掃描器。

輸入內容限制在恰好 8,192 個 UTF-16 碼元以內。ASCII 控制字元、前後的空白字元,以及原始反斜線,都會在建構這個 URL 之前就被拒絕,因此貼上的換行符號或不小心夾帶的定位字元,不會被靜默剔除。查詢參數限制在恰好 200 筆以內,完整格式化後的 JSON 輸出,則獨立限制在 50,000 個碼元以內。恰好在邊界上的值會被接受;超過一個單位或一筆的則會被拒絕。沒有任何東西會被靜默截斷、取樣或跳過。

憑證處理是最嚴格的一條規則。任何含有非空使用者名稱或密碼的網址,都會在建構任何欄位之前就被拒絕。這個工具不會顯示、部分遮蔽,或編修使用者資訊,因為即使是部分遮蔽的輸出,也可能保留一個敏感的使用者名稱、暗示密碼長度,或被複製進日誌中。因此 https://user:[email protected] 會產生一個憑證錯誤,不會有任何剖析出來的欄位,即使底層的 URL API 其實會樂於剖析它。查詢字串與片段,同樣可能帶有應用程式的機密資訊,而這些會被呈現出來,因為它們是所請求網址組成部分的一部分——在複製 JSON 或分享結果之前,請先檢視它們。

如果你更改輸入內容,舊的結果、錯誤訊息、查詢清單、摘要、輸出內容與剪貼簿狀態,都會立即被清除。重新執行一次,會從一個乾淨的狀態開始,一次失敗的網址,絕不會讓先前成功的結果殘留在畫面上。剪貼簿寫入是非同步且有世代防護的,因此一個在你已經編輯過輸入內容之後才完成解析的剪貼簿權限,不會為先前的結果發布一個帶有誤導性的「已複製」狀態。如果你想更深入了解查詢參數是如何被解碼的——特別是加號轉空格的行為——MDN URLSearchParams reference詳細說明了瀏覽器遵循的每一條規則。

網址與文字處理相關工具

如果你特別想把查詢字串轉換成一個結構化的 JSON 物件,而不是一個依序排列的陣列,請參閱parsing URL query strings into JSON這篇指南。那篇文章用同樣以瀏覽器為基礎的做法,逐一介紹加號、重複的鍵,以及百分比編碼值。

如果你想處理這個檢視工具產生出來的 JSON——在貼到別處之前重新格式化、驗證,或壓縮——JSON FormatterJSON Validator都在你的分頁中本機執行。若要查詢對那個網址發出真實請求會回傳什麼 HTTP 狀態碼,可以瀏覽HTTP Status Codes參考資料。

URL Parser 並不能取代真正開啟連結、檢查憑證,或解析 DNS 紀錄。它是一個針對網址文字本身、確定性的 WHATWG 讀取工具,而這正是你可以複製進剪貼簿、複製進錯誤回報,或複製進測試夾具的那一部分。

相關閱讀:VS Code Keyboard Shortcuts: Find and Change the Default