jsonpはなぜ必要か
最近のWEBアプリケーションは、サーバーでHTMLを生成する方法ではなく、サーバーは要求されたデータをjsonで返し、クライアントがajaxを用いてそのjsonデータを受け取りにいき画面に反映する、という手法をとる。
ajaxを行う際、最初のHTMLを生成したサーバーと同じサーバーに通信を行うのであれば問題はないが、異なるサーバーにデータを取りにいこうとすると、javascriptのセキュリティの制限を受けて、通信をすることができない。
そこでjsonpという方法が登場し、この問題を解決する。
jsonpの動作原理
HTMLでは、<script>
タグで読み込むjsは、最初のHTMLを生成したサーバーと異なっていてもよい。そして、srcに指定するのは、js以外のURLでもかまわない。
この性質を使って、別サーバーのURLを呼び出すことにする。
ここでは、当然、jsonを返すURLを指定する。たとえば、phpによるWEBアプリケーションを示してみる。(http://domain/json.phpとしよう)
<?php
$RESPONSE['data1']='val1';
$RESPONSE['data2']='val2';
header('Content-Type: text/javascript; charset=utf-8');
echo sprintf("xcallback(%s);",json_encode($RESPONSE));
?>
このプログラム(http://domain/json.php)を呼び出すと、
xcallback({"data1":"val1","data2":"val2"});
という出力を得る。
これを
<script type="text/javascript" src="http://domain/json.php"></script>
としてHTMLから呼び出すと、Fig2の出力は、javascriptとして認識される。
もし、xcallback(json)という関数が存在すれば、それが呼び出される。なければエラーになる。xcallback(json)を定義して、HTMLにデータを書き出すようにしてみよう。
<html>
<head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/2.2.2/jquery.min.js"></script>
<script>
function xcallback(json) {
$('#json').text('json:'+JSON.stringify(json));
}
</script>
</head>
<body>
<div id="json"></div>
</script><script type="text/javascript" src="http://domain/json.php"></script>
</body>
</html>
このhtmlファイルは、domain
と異なるサーバーにおいて実行することができる。なんならローカルファイルとしてブラウザに読み込んでも問題なく実行できる。
なお、xcallbackを呼び出しは、すべての準備が整ってからでなければならないので、json.phpのローディングが最後になるように配置した。
json.phpを呼び出した結果、xcallbackが呼び出される、という動きはこれで理解できたと思う。しかし、このままでは、任意の時点でサーバーにデータを要求できるとは思えない。json.phpの呼び出しを動的に行うように変更してみよう。これはjQueryを使うなら簡単だ。$.getScript()でスクリプトを追加できる。
<html>
<head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/2.2.2/jquery.min.js"></script>
<script>
function xcallback(json) {
$('#json').text('json:'+JSON.stringify(json));
}
$(document).ready(function(){
$.getScript("http://domain/json.php");
});
</script>
</head>
<body>
<div id="json"></div>
</body>
</html>
以上の説明でjsonpの動作原理がわかるだろう。$.getScript()を呼び出せば、その時点でのjson.phpが返す値がxcallback関数にわたり処理される、ということも容易に想像できるはずだ。
ただ、Fig5では、固定のjsonが返ってくるだけのサンプルなので、ありがたみがいまひとつ感じられないだろう。データのやり取りを動的に行う方法を次にしめしたいと思う。
jQuery-jsonp.jsを使った実用的なjsonp呼出し
jQueryの$.ajax
で、jsonpを利用することもできるが、ファイルがないとか、なんらかの事情でエラーが発生した場合に、正しくエラーハンドリングを行うことができない。エラーが発生するとだんまりになるのだ。
そこで、ここでは、jQuery-jsonp.jsの$.jsonp
を使う方法を示そう。
$.jsonp
を使うと、動作原理で示した方法を内部で実行してあたかも$.ajax
のような振る舞いでjsonpの呼び出しを行ってくれるのだ。
ここでは、サンプルといえども実用的であるために、クライアントからデータ(json)を送信し、それをphpで受け取り、そのままjsonで返すという仕組みにすることにした。
まずは、クライアントのプログラムから示す。
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/2.2.2/jquery.min.js"></script>
<script type="text/javascript" src="http://cloud.github.com/downloads/jaubourg/jquery-jsonp/jquery.jsonp-2.4.0.js"></script>
<script>
$(document).ready(function(){
$.jsonp({
cache: false,
url: 'http://domain/json.php',
data: {"postIntData1" : 2,"postStringData2" : "test2"},
callback: 'xcallback',
timeout: 10000,
success: function(json, textStatus, xOptions) {
$('#success').text('success:'+JSON.stringify(json));
},
error: function(xOptions, textStatus) {
$('#error').text('error:xOptions='+xOptions+',textStatus='+textStatus);
}
});
});
</script>
</head>
<body>
result<hr>
<div id="success"></div>
<div id="error"></div><hr>
</body>
</html>
$.ajax
の代わりに$.jsonp
としているだけのように見えるほど、$.ajax
と呼出方が似ていることがわかってもらえるだろう。($.ajax
を知っていることが前提になりますが)
data:のところに記載しているものは、クライアントからサーバに送るデータである。今回は、jsonの値をそのまま書いてしまったが、通常は、ここに変数を書くのが普通であろう。
<?php
if(!empty($_POST)) {
$METHOD='POST'; //jsonpではPOSTメソッドで呼び出されることはない
$REQ=$_POST;
} elseif(!empty($_GET)) {
$METHOD='GET';
$REQ=$_GET;
}
$RESPONSE['HOST']=$_SERVER['SERVER_NAME'];
$RESPONSE['METHOD']=$METHOD;
$RESPONSE['DATA']=$REQ;
header('Content-Type: text/javascript; charset=utf-8');
echo sprintf("xcallback(%s);",json_encode($RESPONSE));
サーバープログラムは呼び出された際のデータをオウム返ししているだけであるが、このようなプログラムを使うと、実際にどのようなデータが渡ってきているのが良く理解できるので、開発を行う前に用意しておくとよいものの1つであると思う。
動作原理でもわかるように、jsonpの呼び出しは'GET'メソッドだけである。'POST'されることはないのだが、このプログラムを使うそれが良く理解できるはずだ。(試しに$.ajax
でPOST呼出してみると良い)