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>
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の形式ではなく、データを単純な配列などで返す場合を
考えてみる。
下記の様なケース。
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でもなんとかやろうとするのであらば、
下記のようになるだろう。
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(のコールバック関数の仕組み)
ということでいいのかな。