Node.jsにおいてURL(Uniform Resource Locator)を適切に扱うことは、Webアプリケーション開発における最も基礎的かつ重要な要素の一つです。

2026年現在のNode.js(v26.2.0以降)では、従来のレガシーなAPIからWeb標準であるWHATWG URL APIへの完全な移行が推奨されています。

ネットワークを介したデータのやり取りが複雑化する中で、ブラウザとサーバーサイドで一貫したURL操作を行うことは、バグの抑制とセキュリティの向上に直結します。

本記事では、Node.jsのurlモジュールの基礎から、最新のWeb標準APIを用いた具体的な操作方法、そして移行時の注意点について詳しく解説します。

Node.jsにおけるURLモジュールの役割と現状

Node.jsのurlモジュールは、URL文字列の解析、構築、および変換を行うための標準機能を提供しています。

歴史的にNode.jsには、独自の「レガシーAPI(url.parseなど)」と、Webブラウザと共通の「WHATWG URL API」の2種類が存在してきました。

2026年時点では、レガシーAPIは非推奨(Deprecated)の扱いとなっており、新規開発において使用することは推奨されません。

現代的な開発では、グローバルに提供されているURLクラスを利用することが一般的となっています。

この移行の背景には、セキュリティ上の脆弱性を回避し、JavaScriptエコシステム全体でURLの解釈を一貫させるという強い目的があります。

WHATWG URL APIの基本操作

Node.jsでURLを操作する際の中心となるのが、URLオブジェクトです。

このオブジェクトを使用することで、複雑なURL文字列を構造化されたデータとして扱うことができます。

URLオブジェクトのインスタンス化

URLオブジェクトを作成するには、コンストラクタにURL文字列を渡します。

JavaScript
// WHATWG URL APIを使用したURLの解析
const myUrl = new URL('https://user:pass@example.com:8080/p/a/t/h?query=string#hash');

console.log(myUrl.protocol); // プロトコル
console.log(myUrl.hostname); // ホスト名
console.log(myUrl.port);     // ポート番号
console.log(myUrl.pathname); // パス
console.log(myUrl.search);   // クエリ文字列
実行結果
https:
example.com
8080
/p/a/t/h
?query=string

相対パスを使用してURLを生成する場合は、第2引数にベースとなるURL(Base URL)を指定する必要があります。

JavaScript
// ベースURLを指定した相対パスの解決
const baseUrl = 'https://example.com/api/v1/';
const relativePath = 'users/123';

const fullUrl = new URL(relativePath, baseUrl);
console.log(fullUrl.href);
実行結果
https://example.com/api/v1/users/123

URLオブジェクトの主要プロパティ

URLオブジェクトは、URLの各コンポーネントにアクセスするための便利なプロパティを保持しています。

プロパティ名説明
hrefシリアル化された完全なURL文字列https://example.com/path?q=1
originURLのオリジン(プロトコル + ホスト + ポート)https://example.com
protocol末尾のコロンを含むプロトコルスキームhttps:
hostnameポート番号を含まないホスト名example.com
portポート番号(デフォルトポートの場合は空文字列)8080
pathnameスラッシュから始まるパス部分/path
searchParamsクエリパラメータを操作するためのURLSearchParamsオブジェクト(オブジェクト)

URLSearchParamsによるクエリパラメータの高度な操作

URLのクエリパラメータを操作する際、文字列を手動で連結するのはバグの原因となります。

URLオブジェクトのsearchParamsプロパティを使用することで、安全かつ直感的にパラメータの追加・変更・削除が行えます。

パラメータの取得と追加

JavaScript
const url = new URL('https://example.com/search');

// パラメータの追加
url.searchParams.append('page', '1');
url.searchParams.append('sort', 'desc');
// 同じキーで複数追加も可能
url.searchParams.append('filter', 'active');
url.searchParams.append('filter', 'recent');

console.log(url.href);
実行結果
https://example.com/search?page=1&sort=desc&filter=active&filter=recent

パラメータの更新と削除

setメソッドを使用すると、既存の同名キーをすべて削除した上で、新しい値を設定します。

JavaScript
const url = new URL('https://example.com/search?q=nodejs&lang=ja');

// langパラメータを上書き
url.searchParams.set('lang', 'en');

// qパラメータを削除
url.searchParams.delete('q');

console.log(url.search);
実行結果
?lang=en

レガシーAPI(url.parse)からの移行ガイド

かつてNode.jsで標準だったurl.parse()は、現在では使用を避けるべき「レガシーAPI」に分類されています。

レガシーAPIは、URLのパースロジックに特有の癖があり、特定の入力に対してセキュリティリスク(オープンリダイレクト脆弱性など)を引き起こす可能性が指摘されています。

移行すべきコードのパターン

以下のような従来のコードは、WHATWG URL APIへの書き換えが必要です。

JavaScript
// 旧来の書き方(非推奨)
const url = require('url');
const parsed = url.parse('https://example.com/path');
console.log(parsed.hostname);

これを次のように修正します。

JavaScript
// 新しい書き方(推奨)
// ブラウザ互換のため、require('url')なしでもURLクラスは利用可能
const parsed = new URL('https://example.com/path');
console.log(parsed.hostname);

動作の違いに関する注意点

レガシーAPIとWHATWG APIでは、微妙に挙動が異なるプロパティがあります。

例えば、レガシーAPIのsearchプロパティは「?」が含まれますが、WHATWG APIでも同様に「?」が含まれます。

しかし、「パスの一部としてのスラッシュ」の扱いや、特殊文字のエスケープ処理においてWHATWG APIの方が厳格です。

既存のシステムを移行する際は、パース後の文字列が厳密に一致するかどうかテストコードで確認することを強く推奨します。

ファイルパスとURLの相互変換

Node.js特有のユースケースとして、ローカルのファイルパスをURL形式(file://…)に変換したり、その逆を行ったりする場面があります。

特にECMAScript Modules(ESM)環境では、__dirname__filenameが利用できないため、import.meta.urlを処理するためにこれらの関数が重宝されます。

fileURLToPath と pathToFileURL

これらのユーティリティ関数は、node:urlモジュールからインポートして使用します。

JavaScript
import { fileURLToPath, pathToFileURL } from 'node:url';
import path from 'node:path';

// URLをファイルパスに変換
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

console.log(`ファイルパス: ${__filename}`);

// ファイルパスをURLに変換
const filePath = '/usr/bin/node';
const fileUrl = pathToFileURL(filePath);

console.log(`URL形式: ${fileUrl.href}`);
実行結果
ファイルパス: /home/user/project/index.js
URL形式: file:///usr/bin/node

Windows環境とUNIX環境でのパス区切り文字の違い(\ と /)を正しく吸収してくれるため、OSに依存しないコードを書くために必須の知識です。

Node.js特有のユーティリティ関数

urlモジュールには、URLオブジェクト以外にも便利な関数が含まれています。

url.domainToASCII と url.domainToUnicode

国際化ドメイン名(IDN)を扱う際に使用されます。

日本語ドメインなどをPunycode形式に変換したり、その逆を行ったりすることができます。

JavaScript
import url from 'node:url';

const domain = '総務省.jp';
const asciiDomain = url.domainToASCII(domain);
console.log(asciiDomain);

const unicodeDomain = url.domainToUnicode(asciiDomain);
console.log(unicodeDomain);
実行結果
xn--l8jtbt6z.jp
総務省.jp

url.format によるURLのシリアル化

オブジェクトからURL文字列を生成する際、url.format()を使用できます。

WHATWG URLオブジェクトを渡した場合は、単にurl.hrefを取得するのと同じ動作になりますが、オプションを指定してカスタマイズすることが可能です。

JavaScript
const myUrl = new URL('https://example.com/a?b=c');
const formatted = url.format(myUrl, { fragment: false, unicode: true });
console.log(formatted);

実務での活用とセキュリティ上の注意点

URL操作は一見単純に見えますが、外部からの入力を扱う場合には細心の注意が必要です。

例えば、ユーザーから提供されたURLへリダイレクトさせる処理を実装する場合、ホスト名のバリデーションを怠ると、フィッシングサイトへの誘導に悪用される恐れがあります。

バリデーションの例

特定のドメインのみを許可するホワイトリスト形式のチェックは、以下のように実装します。

JavaScript
function isSafeUrl(inputUrl) {
    try {
        const url = new URL(inputUrl);
        const allowedHosts = ['example.com', 'api.example.com'];
        // ホスト名が許可リストに含まれているか確認
        return allowedHosts.includes(url.hostname);
    } catch (e) {
        // 不正な形式のURLはエラーになるため安全ではないと判断
        return false;
    }
}

console.log(isSafeUrl('https://example.com/dashboard'));
console.log(isSafeUrl('https://malicious-site.com/'));
実行結果
true
false

new URL()は、不正な形式の文字列が渡された場合にTypeErrorをスローするため、必ずtry-catchブロックで囲むことが重要です。

また、プロトコルがhttps:であることの確認を組み合わせることで、より強固なセキュリティを確保できます。

まとめ

Node.jsにおけるURLモジュールは、Web標準APIへの準拠を完了し、より安全で移植性の高いツールへと進化しました。

2026年の開発においては、従来のurl.parse()を完全に卒業し、URLクラスおよびURLSearchParamsを活用することが標準的な作法となっています。

これらのAPIはブラウザのJavaScriptと共通であるため、フロントエンドとバックエンドでコードを共有したり、学習コストを削減したりするメリットもあります。

パス操作を行う際にはnode:pathだけでなく、fileURLToPathなどのURL変換ユーティリティを適切に組み合わせることを忘れないでください。

正確なURL処理の知識を身につけることは、堅牢なWebアプリケーションを構築するための第一歩です。

本記事で紹介したテクニックを活用し、一貫性のあるモダンなNode.js開発を推進していきましょう。