沈思黙考：jsonpの仕組み

# 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: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)を呼び出すと、

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

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

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

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

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

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

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

```html: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呼出してみると良い)