在前端與 Node.js 開發中,當我們需要對任意網址字串進行 JS 解析 URL(How to parse URLs in JavaScript)時,早期常見的做法是使用 split() 或正規表達式手動切割字串,但遇到帶有連接埠(Port)、多重路徑或特殊編碼參數時極易出錯。現代瀏覽器與 Node.js 環境皆已內建標準的 new URL() 建構函式,只需一行程式碼即可將網址字串拆解為結構化物件。
💡 系列延伸補充:若你是想直接讀取「瀏覽器當前所在頁面」的網址,可參考另一篇 JavaScript 取得目前 URL 與相關參數:window.location 9 大屬性速查表;本文則專注於解析「任意傳入的 URL 字串變數」。
一、使用 new URL() 解析網址字串基本語法
將合法的完整網址字串傳入 new URL(urlString) 後,會回傳一個包含 protocol、hostname、pathname、search、searchParams 與 hash 等標準屬性的 URL 實例:
// 欲解析的目標網址字串
const inputURL = 'https://www.example.com:8080/path/to/something?category=js&page=2#section-1';
// 建立 URL 解析實例
const url = new URL(inputURL);
console.log(url.href); // 'https://www.example.com:8080/path/to/something?category=js&page=2#section-1'
console.log(url.protocol); // 'https:'
console.log(url.origin); // 'https://www.example.com:8080'
console.log(url.host); // 'www.example.com:8080' (包含連接埠)
console.log(url.hostname); // 'www.example.com' (純網域名稱,不含連接埠)
console.log(url.port); // '8080' (若網址未指定連接埠則為空字串 '')
console.log(url.pathname); // '/path/to/something'
console.log(url.search); // '?category=js&page=2'
console.log(url.hash); // '#section-1'
二、URL 物件常用屬性速查表
以網址 https://seanacnet.com:8443/javascript/post?id=10&tag=web#top 為例,各屬性解析後的回傳值對照如下:
| 屬性名稱 | 解析回傳值範例 | 屬性說明與注意事項 |
|---|---|---|
url.href | 'https://seanacnet.com:8443/javascript/post?id=10&tag=web#top' | 完整標準化後的 URL 字串 |
url.origin | 'https://seanacnet.com:8443' | 來源組合(協定 + 主機名稱 + 連接埠),常用於 CORS 比對 |
url.protocol | 'https:' | 通訊協定名稱(結尾包含冒號 :) |
url.host | 'seanacnet.com:8443' | 主機名稱加上連接埠號 |
url.hostname | 'seanacnet.com' | 純網域名稱(不包含連接埠號) |
url.port | '8443' | 明確指定的連接埠號;若使用預設 80/443 且未寫出則回傳 '' |
url.pathname | '/javascript/post' | 網域後的路徑部分(以 / 開頭) |
url.search | '?id=10&tag=web' | 原始 GET 查詢字串(包含開頭的問號 ?) |
url.searchParams | URLSearchParams { 'id' => '10', 'tag' => 'web' } | 可直接呼叫 .get('id') 讀取參數的物件實例 |
url.hash | '#top' | 頁面錨點片段識別碼(包含開頭的井字號 #) |
三、搭配 searchParams 讀取與修改 GET 查詢參數
new URL() 解析出的實例內建了 url.searchParams 屬性(型別為 URLSearchParams),不需要再手動把 ? 問號切掉,就能直接透過 .get()、.getAll() 或 .set() 操作參數:
const url = new URL('https://www.example.com/products?sort=price&tag=new&tag=sale');
// 1. 取得單一參數值(若不存在會回傳 null)
console.log(url.searchParams.get('sort')); // 'price'
console.log(url.searchParams.get('page')); // null
// 2. 取得同名重複參數的所有值(回傳陣列)
console.log(url.searchParams.getAll('tag')); // ['new', 'sale']
// 3. 檢查參數是否存在
console.log(url.searchParams.has('sort')); // true
// 4. 動態新增或修改參數,url.href 會自動同步更新並完成 URL 編碼
url.searchParams.set('page', '3');
url.searchParams.append('keyword', '前端開發');
console.log(url.toString());
// 'https://www.example.com/products?sort=price&tag=new&tag=sale&page=3&keyword=%E5%89%8D%E7%AB%AF%E9%96%8B%E7%99%BC'
四、解析相對路徑與無效網址的防呆處理
在實務專案中使⽤ new URL() 時,有兩個常見的執行期錯誤(TypeError: Failed to construct 'URL': Invalid URL)需要特別防範:
1. 解析相對路徑時必須傳入第二個 base 參數
如果傳入的字串是 /api/v1/users 這類不含網域的相對路徑,單獨呼叫 new URL('/api/v1/users') 會直接拋出錯誤。此時只需在第二個參數傳入基準網域(例如 window.location.origin):
// 傳入第二個參數作為 Base URL 即可安全解析相對路徑
const apiUrl = new URL('/api/v1/users?limit=20', 'https://seanacnet.com');
console.log(apiUrl.href); // 'https://seanacnet.com/api/v1/users?limit=20'
console.log(apiUrl.pathname); // '/api/v1/users'
2. 使用 URL.canParse() 或 try...catch 驗證使用者輸入
當網址來源是外部 API 或使用者表單輸入時,建議先使用現代環境支援的 URL.canParse()(或 try...catch)確認格式合法後再解析,避免整個前端畫面崩潰:
function safeParseUrl(rawString, baseOrigin = undefined) {
// 若環境支援標準 URL.canParse (Chrome 113+, Firefox 115+, Safari 17+, Node.js 19.9+)
if (typeof URL.canParse === 'function') {
return URL.canParse(rawString, baseOrigin) ? new URL(rawString, baseOrigin) : null;
}
// 相容舊環境的 try...catch 降級寫法
try {
return new URL(rawString, baseOrigin);
} catch {
return null;
}
}
const parsed = safeParseUrl('not-a-valid-url');
console.log(parsed); // null(不會中斷程式執行)