2018年8月31日

[JS] 使用 JavaScript 解析網址與處理網址中的參數(URL Parameters)

keywords: parse URL, parameter, URL, query string
由於前後端分離的趨勢,很多的前端網頁都是透過 API 的方式向後端要資料,而最普遍的就是使用 GET 方法在網址後面加上「參數(parameters)」或稱「查詢字串(query string)」來向後端索取資料。
Imgur
由於在瀏覽器內建用來發送 AJAX 請求的 Fetch API 似乎除了把整個 URL 代進去之外,好像沒有看到其他比較漂亮用來設定網址參數的方法,但是網址參數的部分有時候真的是又臭又長,把它整個放進去實在不太好閱讀
找了一下,發現其實不需要額外裝什麼套件就可以處理網址的解析和網址參數的設定,瀏覽本身提供了 URLURLSearchParams 的 WebAPIs 可以使用。
// 直接把網址參數代入
fetch('https://github.com/search?q=react&type=Code')
  .then(function(response) {
    // Do something ...
  })
如果對於網址各部分的名稱不太清楚,可以參考這篇:網址 URL 英文大小寫是否有差別?
讓我們來看一下可以怎麼使用這些 API 來解析網址和設定網址中的參數

解析網址(Parsing URL)

要解析網址的話,可以使用瀏覽器內建的 URL 這個 Web API,使用的方式很簡單,把網址代進去 URL 建構式就可以了:
let githubURL = new URL('https://github.com/search?q=react&type=Code');
建立好了之後就可以使用幾個不同的屬性來取得網址的內容:
// 取得完整網址(URL)
githubURL.href;      // "https://github.com/search?q=react&type=Code"

// 取得網址中的主機名稱
githubURL.hostname;     // "github.com"

// 取得網頁路徑部分
githubURL.pathname;   // "/search"

// 取得網址中的通訊協定部分
githubURL.protocol;    // "https:"

// 取得網頁參數部分
githubURL.search;     // "?q=react&type=Code"
githubURL.searchParams;  // URLSearchParams {}
透過把網址輸入 URL 建構式之後,瀏覽器幾乎把所有網址的部分都解析完了,透過 githubURL.search 這個方法雖然可以取得完整的網址參數部分,但是還沒有把內容完全解析出來,這時候可以使用 githubURL.searchParams 這個物件。

URLSearchParams

githubURL.searchParams 這個物件是透過另一個名為 URLSearchParams 的 Web API 所建立的,透過這個 API 可以很方便的幫去設定、刪除和讀取網址字串的部分。
想要檢視這個 URLSearchParams 物件最簡單的方是直接使用 toString() 方法:
// 檢視 URLSearchParams 物件
githubURL.searchParams.toString();      // "q=react&type=Code"
假設我們要取得解析後的網址參數,只需要使用 .entries() 方法搭配 for ... of 就可以:
let params = githubURL.searchParams;
for (let pair of params.entries()) {
  console.log(`key: ${pair[0]}, value: ${pair[1]}`)
}
如此就可以把整個網址參數的部分解析出來:
key: q, value: react
key: type, value: Code
除了可以把網址參數的部分解析出來外,它還提供了像是 .has(<key>).get(<key>) 的方法,可以檢驗特定的參數是否存在,並取得其值:
let params = githubURL.searchParams;
params.has('q');    // true
params.get('q');    // "react"
其實如果你對於 ES6 當中的 Map 物件有印象的話,你會發現 URLSearchParams 的用法就和 Map 的用法大同小異。

設定網址參數(URL parameters)

除了前面提過的, URLSearchParams 物件可以解析網址參數之外,它還可以用來設定網址參數,有幾種不同的設定方式,這幾種寫法會得到一樣的結果:
let githubURL = new URL('https://github.com/search');

// 方法一:直接寫入
var searchParams = new URLSearchParams('q=react&type=Code');

// 方法二:代入陣列
var searchParams = new URLSearchParams([['q', 'react'], ['type', 'Code']]);

// 方法三:代入物件
var searchParams = new URLSearchParams({q: 'react', type: 'Code'});

// 都會得到一樣的結果
searchParams.toString() // "q=react&type=Code"
設定好網址參數後最後我們只需要把這個 URLSearchParams 物件代入原本的 URL 物件中就可以了:
githubURL.search = searchParams;
githubURL.href; // "https://github.com/search?q=react&type=Code"
另外,在 URLSearchParams 中,還提供了 .set(), .append(), .sort(), .delete() 的方法可以讓你才操作這些網址參數,有興去的話可以到 MDN 上看一下。

實作

解析網址中的網址參數

假設我們想要解析這段網址:
https://www.google.com.tw/search?hl=zh-TW&as_q=react&&lr=lang_zh-TW&cr=countryTW&as_qdr=all&as_occt=any
const googleSearchURL = new URL('https://www.google.com.tw/search?hl=zh-TW&as_q=react&&lr=lang_zh-TW&cr=countryTW&as_qdr=all&as_occt=any');

// 透過物件的解構賦值,取出 URL 物件的屬性值
const { href, protocol, hostname, pathname, search, searchParams } = googleSearchURL;

// 透過陣列的解構賦值,取得網址參數部分
for(let [key, value] of searchParams.entries()) {
  console.log(`key: ${key}, value: ${value}`)
}

// 取得所有 key-value,回傳陣列
[...searchParams];

設定網址參數代入 fetch API 中

原本要直接把整個網址代入 fetch API 內:
// 原本的寫法
const googleURL = 'https://www.google.com.tw/search';
const searchParams = 'as_occt=any&as_q=react&as_qdr=all&cr=countryTW&hl=zh-TW&lr=lang_zh-TW';

// fetch API
fetch(`${googleURL}?${searchParams}`).then();
使用 URLSearchParams 後可以把參數整理的比較乾淨再放入:
const googleURL = new URL('https://www.google.com.tw/search');
let searchParams = new URLSearchParams({
  as_occt: "any",
  as_q: "react",
  as_qdr: "all",
  cr: "countryTW",
  hl: "zh-TW",
  lr: "lang_zh-TW"
});

googleURL.search = searchParams;

// fetch API
fetch(googleURL.href).then();

參考資料

  • URL @ MDN > Web technology for developers > Web APIs
  • URL SearchParams @ MDN > Web technology for developers > Web APIs

0 意見:

張貼留言