紀錄工作經驗、相關知識,解決技術相關問題。

Javascript, React, 新手 Jamp Holes, 網站相關

JS 解析 URL (How to parse URLs in JavaScript):new URL 與 URLSearchParams 屬性對照

JS 解析 URL (How to parse URLs in JavaScript):new URL 與 URLSearchParams 屬性對照 特色圖片

在前端與 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.searchParamsURLSearchParams { '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(不會中斷程式執行)

參考資料與延伸閱讀