入門 JSON 3 -- JSONP とコールバック関数

no extension

最近 JSONP というのが話題になっているようですので, ここで簡単に紹介します。

JSONP (JSON with Padding)というのは JSON のデータフォーマットにちょっとした記述を加えて JavaScript の関数として呼び出せるようにしたものです。 JSONP については以下の記事に簡単な説明があります。(多分この記事が初出だろうという話です)

例えば以下のような JSON データがあるとします。

{ "name" : "Yasuhiro ARAKAWA" }

JSONP ではこのデータに記述を加えて JavaScript 関数のようにしたものです。 分かりにくいですね。 具体的にはこのように記述します。

callback( { "name" : "Yasuhiro ARAKAWA" } );

"callback" の部分は関数の名前として使えるものなら何でもいいです。 例えば

funclist[1234]( { "name" : "Yasuhiro ARAKAWA" } );

でも構いません。 何でこんなことをするかというと, JavaScript で他ドメインの JSON データを非同期で読み込むことができるからです。

以前「入門 JSON」にて, JavaScript でリモートのデータを呼び込む際に2通りの方法があると説明しました。 ひとつは XMLHttpRequest クラスを使う方法, もうひとつは JavaScript ソースとしてインクルードする方法です。 「クロスドメインの制約」からXMLHttpRequest を使う方法では読込先が他ドメインの場合は使えません。 そこでデータを JSONP の形式にして JavaScript のソースとしてインクルードしてしまうわけです。 また JSONP は関数呼び出しの形式になっているので, その関数の処理を別に記述することでコールバック関数のように機能します。

JSONP を上手く処理するためのクラスを公開しておられる方もいます。

この記事で公開している jsr_class.js というソースファイルがそれです。 このソースでは JSONscriptRequest というクラスが定義されています。 早速使ってみましょう。 実はソーシャル・ブックマーク・サービスの del.icio.us では JSONP 形式のフィードも提供しています。 例えば私のブックマーク(http://del.icio.us/spiegel)を JSONP 形式で取得するには以下のように URI を指定します。

spiegel の部分には del.icio.us のユーザ名が入ります。 また hundler の部分には任意の関数名を指定します。 ここで指定した関数がコールバック関数となります。 試してみると分かりますが, この URI を呼び出すと以下のような文字列が得られます。

hundler([ ... ])

[ ... ] の部分が JSON 形式の配列データになっているわけです。

ところで余談ですが, ついに JSON フォーマットが RFC4627 として正式な仕様になりました。 メディアタイプも application/json と決まりました。 以前「入門 JSON 2」で 「JSON ではこのオブジェクトがデータの基本になっています」 と書きましたが, RFC4627 によると

"A JSON text is a serialized object or array."

とあり, オブジェクト(=連想配列)と配列のどちらでもいいようです。

では JSONP データと JSONscriptRequest クラスを使ってブックマークのリストを作ってみましょう。

<script type="text/javascript" src="/js/jsr_class.js"></script>
<div id="bookmark"></div>
<script type="text/javascript">
  var oJsr = new JSONscriptRequest('http://del.icio.us/feeds/json/spiegel?callback=hundler');
  oJsr.buildScriptTag();
  oJsr.addScriptTag();

function hundler(data) { var ul = document.createElement('ul'); for (var i=0, post; post = data[i]; i++) { var li = document.createElement('li'); var a = document.createElement('a'); a.setAttribute('href', post.u); a.appendChild(document.createTextNode(post.d)); li.appendChild(a); ul.appendChild(li); } document.getElementById('bookmark').appendChild(ul); oJsr.removeScriptTag(); } </script>

(2020−07−31追記:実行結果表示は削除した)

JSONscriptRequest クラスには3つのメソッドがあります。 1つ目は buildScriptTag メソッド。 コンストラクタ引数の URI から script 要素(タグ)を生成します。 2つ目は addScriptTag メソッドで, buildScriptTag で生成した script 要素を HTML の head 要素内に追加します。 簡単に言うと addScriptTag メソッドを呼び出した時点で URI 先のデータが読み込まれコールバック関数が実行されます。 3つ目の removeScriptTag メソッドは生成した script 要素を HTML の head 要素から削除します。 後始末係ですね。

JSONP や JSONscriptRequest クラスは JSON データの使い勝手を向上させますが, 「入門 JSON」でも指摘した通り, この方法は常にセキュリティ上のリスクが伴うことを忘れないでください。 とくに JSONP はサーバ側の実装によっては重大な XSS 脆弱性を抱える可能性があります。 この記事が参考になれば幸いです。

参考: