Node.js API (url) - URL 文字列の解析と生成

URL 「統一資源位置指定子(Uniform Resource Locator)」 というのは Web 上の html ファイルなどのリソースを指定するもので、 ブラウザーなどのアドレスに使われます。
Node.js では 標準モジュール の一つである URL モジュールで URL の文字列の解析、生成などの機能が提供されています。 今回はその URL モジュールおよびそれに関連する Query String モジュールについて紹介します。

URL モジュールは 'url' を require して使用します。
 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#elemid
protocol、 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.js 
node コマンドの使い方について詳しくは以前の記事をご覧ください。

続きを読む

スポンサーサイト



 
このページをシェア
アクセスカウンター
アクセスランキング
[ジャンルランキング]
コンピュータ
31位
アクセスランキングを見る>>

[サブジャンルランキング]
プログラミング
5位
アクセスランキングを見る>>
カレンダー(アーカイブ)
プルダウン 降順 昇順 年別

03月 | 2016年04月 | 05月
- - - - - 1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30


はてな新着記事
はてな人気記事
ブロとも申請フォーム
プロフィール

yohshiy

Author:yohshiy
職業プログラマー。
仕事は主に C++ ですが、軽い言語マニアなので、色々使っています。

はてブ:yohshiy のブックマーク
Twitter:@yohshiy

サイト紹介
プログラミング好きのブログです。プログラミング関連の話題や公開ソフトの開発記などを雑多に書いてます。ただ、たまに英語やネット系の話になることも。