URL 解析器

使用 WHATWG URL 標準把任意 URL 拆解為協議、主機、埠、路徑、查詢和片段,並把查詢引數解碼成可讀表格。

把一條 URL 拆成瀏覽器看到的每個組成部分。 貼上 URL,工具會用與瀏覽器完全相同的 WHATWG 解析器提取各部分,因此結果就是這條 URL 實際會被如何解釋。查詢引數會解碼後列成表格。

查詢引數

URL 的解剖結構

URL 的骨架

每條絕對 URL 都遵循同一個骨架:

scheme://user:password@host:port/path?query#fragment

大多數 URL 只用到其中幾段,但語法上始終允許全部存在。讀懂一條 URL,本質上就是知道每一段在哪裡結束、下一段從哪裡開始 —— 這由 ://@:/?# 這幾個分隔符決定。

逐段拆解

協議(scheme) 指明如何獲取資源:https:mailto:ftp:。注意 WHATWG 解析器返回的值包含結尾冒號,很多人拿它去和字串 "https" 比較時會踩坑。

使用者名稱與密碼 屬於已廢棄的 userinfo 段。瀏覽器仍會解析,但會從請求中剝離並常常給出警告,因為把憑據寫進 URL 會讓它洩漏到歷史記錄、日誌和 referrer 頭裡。如果你在一條不是自己寫的 URL 裡看到它們,應當視為釣魚訊號。

主機名(hostname) 只是域名或 IP。主機(host) 在存在非預設埠時會帶上埠,這也是這兩個欄位經常看起來一樣的原因。

在使用協議預設值時為空 —— https 是 443,http 是 80。解析器會做歸一化:example.com:443/ 報告的埠為空,因為 443 沒有提供任何額外資訊。

路徑 是從第一個 / 到查詢之前的全部內容。對 http(s) URL 來說,它是唯一永遠不為空的部分;只有源的 URL 會得到 / 作為路徑。

查詢字串? 開始,承載引數。片段# 開始,是唯一永遠不會發送給伺服器的部分 —— 它完全由客戶端處理,這正是早期單頁應用用它做路由的原因,也是把訪問令牌放在片段裡能避開服務端日誌的原因。

源(origin) 是協議、主機、埠這個與安全相關的三元組。只有三者全部相同,兩條 URL 才同源,而同源策略和 CORS 判定正是基於它。

解析器為什麼這麼嚴格

WHATWG URL 解析器只接受絕對 URL。example.com/page 沒有協議,無法單獨解析 —— 解析器無從判斷你指的是 example.com/page 還是一個相對路徑。真實程式碼會拿基準 URL 去解析相對引用;本工具刻意要求絕對形式,這樣你看到的結果不會有歧義。

你會注意到的歸一化

解析器不會原樣返回輸入字串。它會把協議和主機轉為小寫、消解路徑中的 ... 段、去掉預設埠,並把國際化域名轉成 Punycode 形式,所以 münchen.de 報告的主機名是 xn--mnchen-3ya.de。這是特性而非缺陷:它展示的是網路棧實際對待這條 URL 的樣子,而不是你敲進去的樣子。

重複的引數

查詢字串完全可以重複同一個鍵,比如 ?tag=a&tag=b。沒有任何規範規定這該如何解釋 —— 有的框架取第一個值,有的取最後一個,有的收整合陣列。這裡的表格按順序列出每一次出現,讓你看到實際傳送的內容,而不是被合併後的檢視。

開源說明:使用瀏覽器內建的 WHATWG URLURLSearchParams API 實現,未使用第三方庫。

常見問題

為什麼埠欄位是空的?
因為這條 URL 用的是該協議的預設埠。WHATWG 解析器會省略 https 的 443 和 http 的 80,因為寫出來不提供額外資訊,反而會破壞源的比較。
協議為什麼帶一個冒號?
這是 URL 標準的定義。protocol 屬性的值是 'https:' 而不是 'https'。如果你要和裸協議名比較,記得處理這個結尾冒號。
host 和 hostname 有什麼區別?
hostname 只是域名本身,host 在存在埠時會帶上埠。對 https://example.com:8443/ 來說,hostname 是 example.com,host 是 example.com:8443。
為什麼不能解析相對 URL?
/about 或 ../img.png 這類相對引用只有相對某個基準 URL 才有意義。解析器要求帶協議的絕對 URL,這樣結果才不會有歧義。
片段會發送給伺服器嗎?
不會。# 之後的內容從不出現在 HTTP 請求裡,完全由瀏覽器處理。這也是 OAuth 隱式流曾用它來避免令牌進入服務端日誌的原因。
我的中文/Unicode 域名為什麼變樣了?
國際化域名會被轉換成 Punycode,也就是 DNS 實際使用的 ASCII 形式。münchen.de 會變成 xn--mnchen-3ya.de。瀏覽器在發起請求前做的正是同樣的轉換。