37
37

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

沈思黙考:jsonpの仕組み

Last updated at Posted at 2016-10-14

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としよう)

Fig1.サーバー(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)を呼び出すと、

Fig2.json.phpをブラウザから呼び出した結果出力
xcallback({"data1":"val1","data2":"val2"});

という出力を得る。
これを

Fig3.HTMLからjson.phpを呼び出す
<script type="text/javascript" src="http://domain/json.php"></script>

としてHTMLから呼び出すと、Fig2の出力は、javascriptとして認識される。
もし、xcallback(json)という関数が存在すれば、それが呼び出される。なければエラーになる。xcallback(json)を定義して、HTMLにデータを書き出すようにしてみよう。

Fig4.
<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()でスクリプトを追加できる。

Fig5.
<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で返すという仕組みにすることにした。

まずは、クライアントのプログラムから示す。

Fig6.クライアントプログラム
<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の値をそのまま書いてしまったが、通常は、ここに変数を書くのが普通であろう。

Fig7.サーバープログラム
<?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呼出してみると良い)

37
37
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
37
37

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?