URLからホスト名やパス、クエリ(?key=value)を取り出したい、あるいはクエリ付きのURLを組み立てたい——Node.jsでは標準のURLとURLSearchParamsでこれらを安全に扱えます。どちらもブラウザと共通のAPIで、追加のライブラリは不要です。古いurl.parse()は非推奨になっており、現在はnew URL()を使うのが正しい方法です。
つまずきやすいのは、相対URL(/pathだけ)は基準となるbaseを渡さないとエラーになること、そして存在しないクエリを取得するとnullが返ることです。また、URLSearchParamsは日本語や記号を自動でURLエンコードしてくれます。この記事では、実機のNode.jsで確認しながら、URLの扱いを整理します。
- URLの分解は
const u = new URL("https://...")。u.hostname・u.pathnameなどで取り出せます。 - クエリは
u.searchParams.get("key")で取得(無いとnull)。 - 相対URLには第2引数のbaseが必要です(
new URL("/path", "https://example.com"))。 - クエリの組み立ては
new URLSearchParams({...})。日本語・記号は自動エンコードされます。 - 同名キーが複数あるときは
getAll("key")で配列として取得します。 fetchのURL組み立てにそのまま使えます。
組み立てたURLで通信するならfetchでAPIを叩く、サーバー側でクエリを受け取るならExpressのreq.query、低レベルな処理はhttpモジュールもあわせて参考になります。
URLを分解する new URL
new URL()に完全なURL文字列を渡すと、各部分にプロパティでアクセスできるオブジェクトになります。プロトコル・ホスト名・ポート・パス・クエリ・ハッシュなどを簡単に取り出せます。
const u = new URL("https://example.com:8080/path/page?name=tanaka&age=30#section");
console.log(u.protocol); // https:
console.log(u.hostname); // example.com
console.log(u.port); // 8080
console.log(u.pathname); // /path/page
console.log(u.search); // ?name=tanaka&age=30
console.log(u.hash); // #section
実機でも、protocol=https:、hostname=example.com、port=8080、pathname=/path/page、hash=#sectionと、URLの各部分が正しく取り出せました。protocolには末尾にコロン(:)が、hashには先頭にシャープ(#)が付く点に注意してください。手で文字列を分割するより、はるかに正確で安全です。
クエリを取得する searchParams
クエリ(?key=value)はu.searchParamsから取得します。get("キー")で値を取り出せます。存在しないキーを指定するとnullが返る点に注意します。
const u = new URL("https://example.com/search?name=tanaka&age=30");
console.log(u.searchParams.get("name")); // tanaka
console.log(u.searchParams.get("age")); // 30(ただし文字列)
console.log(u.searchParams.get("xxx")); // null(存在しないキー)
console.log(u.searchParams.has("name")); // true(あるかどうか)
実機でも、get("name")でtanaka、存在しないget("xxx")ではnullが返りました。取得できる値はすべて文字列なので、数値として使うときはNumber()で変換します。キーがあるかどうかだけ知りたいときはhas()が便利です。undefinedではなくnullが返る点は、判定でif (value === null)のように扱うときに意識しておくとよいです。
相対URLはbaseが必要
ここが注意点です。new URL()に/pathのような相対URL(ホスト名が無いもの)だけを渡すとエラーになります。基準となるURL(base)を第2引数に渡すと、それと組み合わせて解決してくれます。
// NG: 相対URLだけだとエラー
// new URL("/api/users");
// → TypeError: Invalid URL
// OK: 第2引数に base を渡す
const u = new URL("/api/users", "https://example.com");
console.log(u.href); // https://example.com/api/users
// 相対パスの解決にも使える
const u2 = new URL("../images/logo.png", "https://example.com/page/index.html");
console.log(u2.href); // https://example.com/images/logo.png
実機で確認したところ、new URL("/path")のようにホスト名の無い相対URLだけを渡すとTypeError: Invalid URLになりました。一方、new URL("/api/users", "https://example.com")のように第2引数にbase(基準URL)を渡すと、https://example.com/api/usersと正しく解決されました。リンク先のURLやAPIのパスを組み立てるとき、ベースのドメインが分かっているなら第2引数に渡すのが定番です。../のような相対パスも、baseを基準に正しく解決してくれるため、自分でパスを連結するより安全です。フルURL(https://から始まるもの)の場合は、第2引数は不要です。
クエリを組み立てる URLSearchParams
逆に、クエリ文字列を組み立てたいときはURLSearchParamsを使います。オブジェクトを渡すと、key=value&key=valueの形式に変換してくれます。しかも日本語や記号は自動でURLエンコードされます。
const params = new URLSearchParams({
q: "猫 かわいい", // 日本語やスペースを含む
page: "2",
});
console.log(params.toString());
// q=%E7%8C%AB+%E3%81%8B%E3%82%8F%E3%81%84%E3%81%84&page=2
// → 日本語もスペースも自動でエンコードされる
実機で確認したところ、new URLSearchParams({ q: "猫 かわいい", page: "2" })をtoString()するとq=%E7%8C%AB+%E3%81%8B%E3%82%8F%E3%81%84%E3%81%84&page=2となり、日本語はパーセントエンコード、スペースは+に自動変換されました。URLに日本語やスペース、&などの記号をそのまま入れると壊れてしまいますが、URLSearchParamsを使えばエンコードを自分で書く必要がありません。encodeURIComponentを手で呼んで連結するより安全で確実です。検索キーワードやフィルタ条件をクエリにするときは、必ずURLSearchParamsを通すようにしましょう。
同名キー・追加・変更
tag=a&tag=bのように同じキーが複数ある場合はgetAll()で配列として取得します。append()で追加、set()で上書き、delete()で削除もできます。
const params = new URLSearchParams("tag=a&tag=b&tag=c");
console.log(params.get("tag")); // a(getは最初の1つだけ)
console.log(params.getAll("tag")); // ["a", "b", "c"](全部)
// 追加・上書き・削除
params.append("page", "2"); // 追加
params.set("tag", "x"); // tag をすべて x に置き換え
params.delete("page"); // 削除
console.log(params.toString());
実機でも、tag=a&tag=b&tag=cに対してget("tag")は最初のaだけ、getAll("tag")は["a","b","c"]と全部を返しました。同じキーが複数あるかもしれないクエリでは、getだと最初の1つしか取れないので、getAllを使います。appendは同名キーを増やし、setは同名キーをまとめて1つに置き換える、という違いも覚えておくと便利です。
fetchと組み合わせる(実用)
実際のよくある使い方が、fetchでAPIを叩くときのURL組み立てです。new URL()でベースを作り、searchParams.set()でクエリを足していくと、安全にURLを構築できます。
// ベースURLを作り、クエリを足していく
const url = new URL("https://api.example.com/search");
url.searchParams.set("keyword", "node.js");
url.searchParams.set("limit", "10");
console.log(url.href);
// https://api.example.com/search?keyword=node.js&limit=10
// そのまま fetch に渡せる
const res = await fetch(url); // URLオブジェクトを直接渡せる
const data = await res.json();
実機でも、new URL("https://api.example.com/search")にsearchParams.set("keyword", "node.js")を足すと、https://api.example.com/search?keyword=node.jsという正しいURLが組み立てられました。fetchにはURLオブジェクトをそのまま渡せるため、url.hrefに変換する必要もありません。クエリを文字列連結で作ると、エンコード漏れや&の付け忘れでバグになりがちですが、この方法なら安全です。
主なプロパティ・メソッド
よく使うものをまとめます。
| 書き方 | 働き |
|---|---|
new URL(str[, base]) |
URLを分解(相対なら base 必須) |
u.hostname / u.pathname |
ホスト名 / パス |
u.searchParams.get(key) |
クエリの値(無いと null) |
u.searchParams.getAll(key) |
同名キーを配列で取得 |
new URLSearchParams(obj) |
クエリを組み立て(自動エンコード) |
params.set / append / delete |
クエリの編集 |
params.toString() |
クエリ文字列にする |
よくある失敗
相対URLをbaseなしで渡す
Invalid URLエラーになります。第2引数にbaseを渡します。
存在しないクエリの戻り値をそのまま使う
無いキーはnullです。nullチェックをしてから使います。
クエリを文字列連結で組み立てる
エンコード漏れの原因です。URLSearchParamsで自動エンコードします。
同名キーをgetで取ろうとする
getは最初の1つだけです。複数あるならgetAllを使います。
古いurl.parse()を使う
非推奨です。new URL()を使います。
よくある質問
const u = new URL("https://...")で分解し、u.hostnameでホスト名、u.pathnameでパス、u.searchParams.get("key")でクエリの値を取得します。手で文字列を分割するより正確で安全です。/pathのような相対URLをnew URL()にそのまま渡すとこのエラーになります。第2引数に基準となるURL(base)を渡してください。new URL("/api", "https://example.com")のようにすると正しく解決されます。new URLSearchParams({ key: value })を使います。toString()でkey=value&...の形式になり、日本語やスペース、記号は自動でURLエンコードされます。文字列連結で作るとエンコード漏れの原因になるため、この方法が安全です。searchParams.get("key")は最初の1つしか返しません。tag=a&tag=bのように同名キーが複数ある場合は、searchParams.getAll("key")を使うと["a", "b"]のように配列で全部取得できます。url.parse()は古いAPIで非推奨です。現在はnew URL()を使うのが推奨されています。new URL()はブラウザと共通のAPIで、searchParamsによる安全なクエリ操作など機能も豊富です。新しいコードではnew URL()を使ってください。まとめ
- URLの分解は
new URL(str)。hostname・pathname・searchParamsで取り出します。 - クエリ取得は
searchParams.get(無いとnull)、複数はgetAll。 - 相対URLは第2引数のbaseが必要です。
- 組み立ては
URLSearchParams。日本語・記号は自動エンコードされます。 fetchにはURLオブジェクトをそのまま渡せます。
URLの解析と組み立ては、URLとURLSearchParamsに任せるのが安全で確実です。「相対URLはbase」「クエリ組み立てはURLSearchParams」の2点を押さえれば、エンコード漏れやパースミスといった定番のバグを避けられます。fetchと組み合わせて、APIとの連携をすっきり書いてみてください。

