Node.js URL モジュール
1. ビルトイン URL モジュール
URL モジュールは、URL の解決(Resolution)やパース(Parsing)を行うためのユーティリティを提供します。
これを使用することで、Web アドレスを読み取り可能な各パーツに分割したり、URL を新しく構築したり、さまざまな URL コンポーネントを操作したりすることが可能になります。
2. はじめに
URL モジュールを組み込むには、require() メソッドを使用します。
モダンな Node.js(v10.0.0+)では、レガシー API またはより新しい URL クラス(WHATWG URL API) のいずれかを使用できます。
2.1 モジュールのインポート
// レガシー API を使用する場合
const url = require('url');
// モダンな URL クラス(WHATWG API)を使用する場合
const { URL } = require('url');url.parse() メソッドを使用してアドレスをパースすると、アドレスの各パーツがプロパティとして格納された URL オブジェクトが返されます。
例:Web アドレスを読み取り可能なパーツに分割する
let url = require('url');
let adr = 'http://localhost:8080/default.htm?year=2017&month=february';
let q = url.parse(adr, true);
console.log(q.host); // 'localhost:8080'
console.log(q.pathname); // '/default.htm'
console.log(q.search); // '?year=2017&month=february'
let qdata = q.query; // パースされたクエリ情報
console.log(qdata.month); // 'february'3. URL のパースとフォーマット
3.1 URL オブジェクトのプロパティ
URL をパースすると、以下のプロパティを持つ URL オブジェクトが得られます:
- href: パースされたフル URL
- protocol: プロトコルスキーム(例: 'http:')
- host: ポート番号を含むフルホスト部分(例: 'example.com:8080')
- hostname: ホスト名部分(例: 'example.com')
- port: 指定されている場合のポート番号
- pathname: URL のパスセクション
- search: 先頭の
?を含むクエリ文字列 - query:
?なしのクエリ文字列、またはパース済みのクエリオブジェクト - hash: 先頭の
#を含むフラグメント識別子
4. レガシー API vs WHATWG URL API
Node.js では現在、新しいコードには WHATWG URL API の使用が推奨されています。
例:両 API の比較
const { URL } = require('url');
// WHATWG URL API を使用(新規コードに推奨)
const myURL = new URL('https://example.org:8080/p/a/t/h?query=string#hash');
console.log(myURL.hostname); // 'example.org'
console.log(myURL.pathname); // '/p/a/t/h'
console.log(myURL.searchParams.get('query')); // 'string'
// レガシー API を使用
const parsedUrl = require('url').parse('https://example.org:8080/p/a/t/h?query=string#hash');
console.log(parsedUrl.host); // 'example.org:8080'
console.log(parsedUrl.query); // 'query=string'5. URLSearchParams API
URLSearchParams API は、URL のクエリ文字列を操作するための便利なメソッドを提供します。
例:クエリパラメータの操作
const { URL, URLSearchParams } = require('url');
const myURL = new URL('https://example.com/?name=Kai&age=30');
const params = new URLSearchParams(myURL.search);
// パラメータを取得
console.log(params.get('name')); // 'Kai'
// パラメータを追加
params.append('city', 'Stavanger');
// パラメータを削除
params.delete('age');
// 文字列に変換
console.log(params.toString()); // 'name=Kai&city=Stavanger'6. Node.js ファイルサーバーの実装
クエリ文字列のパース方法がわかったところで、以前学んだ HTTP モジュールと File System モジュールを組み合わせて、クライアントからのリクエストに応じてファイルを返すファイルサーバーを構築してみましょう。
まず、Node.js ファイルと同じフォルダに 2 つの HTML ファイルを作成します。
summer.html
<!DOCTYPE html>
<html>
<body>
<h1>夏 (Summer)</h1>
<p>太陽が大好きです!</p>
</body>
</html>winter.html
<!DOCTYPE html>
<html>
<body>
<h1>冬 (Winter)</h1>
<p>雪が大好きです!</p>
</body>
</html>次に、リクエストされたファイルを開き、その内容をクライアントに返す Node.js ファイルを作成します。エラーが発生した場合は 404 エラーを返します。
demo_fileserver.js:
let http = require('http');
let url = require('url');
let fs = require('fs');
http.createServer(function (req, res) {
// リクエスト URL をパース
let q = url.parse(req.url, true);
// パス名からファイルパスを構築
let filename = "." + q.pathname;
// ファイルを読み込む
fs.readFile(filename, function(err, data) {
if (err) {
// ファイルが見つからない場合などは 404 を返す
res.writeHead(404, {'Content-Type': 'text/html; charset=utf-8'});
return res.end("404 Not Found (ファイルが見つかりません)");
}
// 成功した場合は 200 とデータを出力
res.writeHead(200, {'Content-Type': 'text/html; charset=utf-8'});
res.write(data);
return res.end();
});
}).listen(8080);ファイルを起動します:
C:\Users\Your Name>node demo_fileserver.jsブラウザで以下のアドレスを開くと、それぞれ異なる結果が表示されます:
http://localhost:8080/summer.html-> Summer のページを表示http://localhost:8080/winter.html-> Winter のページを表示
7. ベストプラクティス
7.1 URL のバリデーションとサニタイズ
入力された文字列が有効な URL かどうかを常に確認してください。
function isValidHttpUrl(string) {
try {
const url = new URL(string);
return url.protocol === 'http:' || url.protocol === 'https:';
} catch (err) {
return false;
}
}
console.log(isValidHttpUrl('https://example.com')); // true
console.log(isValidHttpUrl('ftp://example.com')); // false7.2 安全な URL の構築
文字列連結ではなく、URL クラスを使用して安全にパスを構築しましょう。
const { URL } = require('url');
// URL を安全に構築するメソッド
function createProfileUrl(domain, username) {
// encodeURIComponent を使用して不正な文字をエスケープ
return new URL(`/users/${encodeURIComponent(username)}`, domain).href;
}
console.log(createProfileUrl('https://example.com', 'johndoe'));
// 'https://example.com/users/johndoe'7.3 クエリパラメータの高度な処理
searchParams を使用すると、既存の URL に対して簡単にパラメータを追加・変更できます。
const { URL } = require('url');
const url = new URL('https://example.com/search?q=node.js&lang=en');
// すべてのパラメータを文字列として取得
console.log(url.searchParams.toString()); // 'q=node.js&lang=en'
// 特定のパラメータを取得
console.log(url.searchParams.get('q')); // 'node.js'
// パラメータが存在するか確認
console.log(url.searchParams.has('lang')); // true
// 新しいパラメータを追加
url.searchParams.append('page', '2');
console.log(url.href);
// 'https://example.com/search?q=node.js&lang=en&page=2'