javascript:JSONPについてのメモ

javascriptに触れる事はなかったのですが、
最近、ちょっと触れる機会がありました。
JSONPの挙動も勉強する事に。
JSONPは良く「クロスドメインと回避するために…」
と言われているが、
クロスドメインを回避しているのは、

のところだよね、と思ったので、
メモがてら整理。


JSONPの動作原理のおさらい

ユーザーがアクセスするサイトのHTMLに
下記のようなコールバック関数を仕込んでおく。

<html>
<body>
<script>
function callback(x){ // コールバック関数を定義
alert(x["name"]);
}
</script>
<script src="http://mail.example.com/json.dat"></script>
</body>
</html>

javascriptタグによるsrcにより読み込まれるjson.datで
コールバック関数に引数を入れたクライアントコードが
返される。

callback( { "name" : "Fukumori" } );

※上記のコードは下記ページを参考
http://gihyo.jp/dev/serial/01/web20sec/0003


◆クロスドメインを避ける方法は他にあるのにJSONPを使う理由を考えてみる。

上記の例だけで言えば、
わざわざこの(コールバック関数を使う)様な仕組みを
使うメリットはない。
srcで読み込んだjsが単純なデータ配列などを返してもらい、
その内容を使うのと変わらない。


では、なぜ使うのか?


上記の例ではユーザーがアクセスしたサイトのHTMLに
コールバック関数があったが、
JSONPを使うメリットは、
ユーザーがアクセスしたサイトのHTMLにjsを読み込み
そのjsが他のドメイン情報を使いたい場合に必要。
なので、実際には、
下記のようなケースが一般的ではないかと思われる。


ユーザーがアクセスしたサイトのHTML

<html>
<body>
<script src="http://siteA.com/siteA.js"></script>
</body>
</html>


http://siteA.com/siteA.js の内容

function callback(x){ // コールバック関数を定義
alert(x["name"]);
}
document.write('<script src="http://siteB.com/siteB_json.js"></script>');


http://siteB.com/siteB_json.js の内容

callback( { "name" : "akamameshiba" } );


siteA.jsはクロスドメインの関係で、
siteBへのアクセスを通常は許されない。
しかし、
それを回避するための方法がJSONPではない、
と言うところを強調したい。
それは、
siteA.js内の
document.write('');
によって回避しているのだよ、ということ。


では、
それでも、なぜJSONPを使うのか?


それは、
document.write('');
の実行タイミングがIEだと、
siteA.jsの終了後に実行される(FFは記述場所で実行する※おそらくエンジン毎で挙動が違うと思われる)ため、
このコールバック関数の機構(JSONP)が始めて生きてくる。


どういう事かというと、
仮に
http://siteB.com/siteB_json.js
JSONPの形式ではなく、データを単純な配列などで返す場合を
考えてみる。
下記の様なケース。


http://siteA.com/siteA.js の内容

document.write('<script src="http://siteB.com/siteB_json.js"></script>');
alert(result['name']);


http://siteB.com/siteB_json.js の内容

result = array('name'->'akamameshiba');


JSONPを使わずに上記のようなやり方の場合、
FFでは問題なくsiteA.jsのalertで取得した内容を
表示出きるが、IEでは、
document.write('');
の実行がsiteA.jsの最後に行われるので、
http://siteB.com/siteB_json.js
のデータを扱うことはでない。
もし、IEでもなんとかやろうとするのであらば、
下記のようになるだろう。


http://siteA.com/siteA.js の内容

document.write('<script src="http://siteB.com/siteB_json.js"></script>');
document.write('<script src="http://siteA.com/siteA_2.js"></script>');


http://siteA.com/siteA_2.js の内容

alert(result['name']);


こんな面倒なことやりたくない、を
解決するのがJSONP(のコールバック関数の仕組み)
ということでいいのかな。