Node.js API (url) - URL 文字列の解析と生成
URL 「統一資源位置指定子(Uniform Resource Locator)」 というのは
Web 上の html ファイルなどのリソースを指定するもので、
ブラウザーなどのアドレスに使われます。
Node.js では 標準モジュール
の一つである URL モジュールで URL の文字列の解析、生成などの機能が提供されています。
今回はその URL モジュールおよびそれに関連する Query String モジュールについて紹介します。
var url = require('url');
URL の解析
URL の文字列は parse 関数で各要素に分解したオブジェクトを取得できます。url.parse(urlStr[, parseQueryString][, slashesDenoteHost])
URL の要素
普段、ユーザー名の指定などは使いませんが、 URL では意外と多くの要素を書くことができます。次の文字列を例に要素に分解してみます。
http://user:pass@host.com:8080/p/a/t/h?query=string#hash
要素 | 例 | 説明 |
---|---|---|
protocol | 'http:' | プロトコル(スキーム)の名称。 https:, ftp:, file: など。 大文字でもすべて小文字に変換される。 |
slashes | true | protocol のコロン(:)の後に '//' があるかどうか |
auth | 'user:pass' | 認証情報(ユーザー名:パスワード) |
port | '8080' | ポート番号 |
hostname | 'host.com' | ホスト名 大文字でもすべて小文字に変換される。 |
host | 'host.com:8080' | ホスト名 と ポート番号 を合わせたもの |
search | '?q=string' | 検索文字列。 検索などの文字列の指定に使われることが多いため、 Node.js では GET メソッドのパラメーターを検索、クエリーなどと呼んでいる。 |
query | 'q=string' | 検索文字列の ? 以降 第二引数の指定で、さらにオブジェクトに分解できる。 |
pathname | '/p/a/t/h' | ホストに要求するパス名 |
path | '/p/a/t/h?q=string' | パス名 と 検索文字列 を合わせたもの |
hash | '#elemid' | ページ内の位置を指定するために使う要素 ID。 |
href | 略 | URL の全体。 protocol と host の小文字の変換やエスケープなどがあるので、元の文字列と全く同じとは限らない。 |
var urlStr = 'http://user:pass@host.com:8080/p/a/t/h?q=string#elemid'; url.parse(url.parse(urlStr)); // Url { // protocol: 'http:', // slashes: true, // auth: 'user:pass', // host: 'host.com:8080', // port: '8080', // hostname: 'host.com', // hash: '#elemid', // search: '?q=string', // query: 'q=string', // pathname: '/p/a/t/h', // path: '/p/a/t/h?q=string', // href: 'http://user:pass@host.com:8080/p/a/t/h?q=string#elemid' }
query の解析
parse 関数の第 2 引数を true に設定すると query の部分がオブジェクト(連想配列)に分解されます。url.parse(urlStr, true); // Url { // : // query: { q: 'string' }, // :
ネットワークコンピューター(SMB)表記の解析
Windows ではネットワーク上のコンピューターには "\\コンピューター名\共有フォルダー" のようにアクセスできます。この \ を / にした表記で '//' の後をホスト名として扱いたい場合には parse の第 3 引数に true を設定します。
var smbStr = '//pcname/share/foo'; url.parse(smbStr)); // Url { // : // slashes: null, // : // host: null, // : // hostname: null, // : // pathname: '//pcname/share/foo', // path: '//pcname/share/foo', // href: '//pcname/share/foo' } url.parse(smbStr, false, true)); // Url { // : // slashes: true, // : // host: 'pcname', // : // hostname: 'pcname', // : // pathname: '/share/foo', // path: '/share/foo', // href: '//pcname/share/foo' }
URL の生成
URL の文字列は format 関数で各要素に分解されたオブジェクトから生成できます。url.format(urlObj)
URL の要素
href、path など一部使わない要素がありますが、基本的に使う要素は解析時と同じものです。要素 | 例 | 説明 |
---|---|---|
protocol | 'http' |
コロン(":") はあってもなくても自動的に不可 http, https, ftp, gopher, file の場合は '//' が生成時に追加される。 mailto や foo などそれ以外の場合は追加されない。 |
slashes | true |
これを true に設定すると mailto などの場合でも '//' は追加。 ただし、http などでは false にしたとしても追加。 |
auth | 'user:pass' | 指定されていれば使用 |
port | '8080' | host が指定されていない場合に使用 |
hostname | 'host.com' | host が指定されていない場合に使用 |
host | 指定されていれば、それが使われ、そうでなければ port と hostname から作成 | |
search | 'q=string' | 指定されていれば使用。 "?" はあってもなくても自動的に不可 |
query | host が指定されいない場合に使用。文字列またはオブジェクトで指定 | |
pathname | 'p/a/t/h' | 先頭の "/" はあってもなくても自動的に不可 |
path | 生成時には使用しない | |
hash | 'elemid' | 指定されていれば使用。 先頭の "#" はあってもなくても自動的に不可 |
href | 生成時には使用しない |
var urlObj = { protocol: 'http', auth: 'user:pass', port: '8080', hostname: 'host.com', hash: 'elemid', search: 'q=string', pathname: 'p/a/t/h' }; url.format(urlObj); // http://user:pass@host.com:8080/p/a/t/h?q=string#elemidprotocol、 slashes によって、 "//" の付く、付かないのサンプルです。
// http などではない → "//" は付かない urlObj = { protocol: 'foo', hostname: 'host.com', pathname: '/p/a/t/h' }; url.format(urlObj); // foo:host.com/p/a/t/h // http などではないが、 slashes を true → "//" が付く urlObj = { protocol: 'foo', slashes: true, hostname: 'host.com', pathname: '/p/a/t/h' }; url.format(urlObj); // foo://host.com/p/a/t/h // http だけど、 slashes を false → "//" は付く urlObj = { protocol: 'http', slashes: false, hostname: 'host.com', pathname: '/p/a/t/h' }; url.format(urlObj); // http://host.com/p/a/t/hまた、 http などであってもホスト名がない場合は '//' は表示されません。 その場合も slashes を true にすると '//' が表示されるようになります。
// file だけどホスト名がない urlObj = { protocol: 'file', pathname: '/C:/foo/bar' }; url.format(urlObj); // file:/C:/foo/bar // file 、ホスト名がなし、 slashes を true urlObj = { protocol: 'file', slashes: true, pathname: '/C:/foo/bar' }; url.format(urlObj); // file:///C:/foo/bar
相対 URL の展開
ある URL から相対的な URL を生成する場合には resolve メソッドを使用します。url.resolve(from, to)例えば、あるページ("http://host.com/foo/index.html")にリンク(<a href="../bar/baz.html">xxxx</a>)があったとして、 そのリンク先の URL はどんな値になるかというのを調べるのに使えます。
url.resolve("http://host.com/foo/index.html", "../bar/baz.html"); // http://host.com/bar/baz.html
クエリー文字列
クエリー文字列は URL の解析、生成と一緒に解析、生成できます。 querystring モジュールを require すると、それだけ使うこともできます。 parse で解析、 stringify で生成です。var querystring = require('querystring'); querystring.parse('foo=bar&baz=qux&baz=quux&corge'); // { foo: 'bar', baz: [ 'qux', 'quux' ], corge: '' } querystring.stringify({ foo: 'bar', baz: [ 'qux', 'quux' ], corge: '' }); // foo=bar&baz=qux&baz=quux&corge=
エスケープ
URL ではスペースなどの一部記号や日本語など使えない文字があり、それらは % を使った表記にエスケープする必要があります。クエリー文字列
クエリー文字列のオブジェクトでは検索などに使うためか 生成、解析時に自動でエンコード、デコードをしてくれます。var escQstrObj = { protocol: 'http', hostname: 'host.com', pathname: 'search.html', query: {q: '日本語'} }; url.format(escQstrObj); // http://host.com/search.html?q=%E6%97%A5%E6%9C%AC%E8%AA%9E
var escQstrStr = 'http://host.com/search.html?q=%E6%97%A5%E6%9C%AC%E8%AA%9E'; url.parse(escQstrStr, true); // Url { // : // search: '?q=%E6%97%A5%E6%9C%AC%E8%AA%9E', // query: { q: '日本語' }, // pathname: '/search.html', // :ちなみにエンコード、デコードには JavaScript の関数である encodeURIComponent, decodeURIComponent を使用しているようです。
変えることはないと思いますが querystring の関数を直接使う場合はオプションで関数を変えることもできます。
URL
パス名などにクエリー文字列以外の部分に関しては、 生成時にスペースなどの一部記号のみエスケープしてくれます。var escObj = { protocol: 'file', slashes: true, pathname: '/C:/Program%20Files/nodejs/index.html' }; url.format(escObj); // file:///C:/Program%20Files/nodejs/index.htmlただ、解析時にエスケープした文字を戻すということはしません。 逆になぜか解析時にも、空白などのエスケープをします。
しかも、対応しているのは ASCII 文字だけで日本語などの変換はしてくれません。
Wikipedia や Weblio のように検索文字がアドレスのパス名に使われることもありますし、 クエリー文字列以外でもちゃんとエンコード、デコードして欲しい場合があります。
そういう場合は直接 encodeURIComponent, decodeURIComponent を使った方がいいと思います。
var escUrlObj = { protocol: 'https', hostname: 'ja.wikipedia.org', pathname: '/wiki/' + encodeURIComponent('メインページ') }; url.format(escUrlObj); // https://ja.wikipedia.org/wiki/%E3%83%A1%E3%82%A4%E3%83%B3%E3%83%9A%E3%83%BC%E3%82%B8
var escUrlStr = 'https://ja.wikipedia.org/wiki/%E3%83%A1%E3%82%A4%E3%83%B3%E3%83%9A%E3%83%BC%E3%82%B8'; var parsedObj = url.parse(escUrlStr); decodeURIComponent(parsedObj.pathname); // '/wiki/ メインページ'
サンプルコード
記事で使用したサンプルコードは以下のリンクから取得(名前をつけて保存)できます。 これを node コマンドの引数に渡して実行します。 なお、日本語の出力は UTF-8 で行われるため、UTF-8 対応のコンソール(Windows PowerShell など)に出力しないと文字化けします。$ node url.jsnode コマンドの使い方について詳しくは以前の記事をご覧ください。