JSONPについて
これまで投稿したサンプルでは、同一出身ポリシーに基づき、
同一サーバ、同一ドメインでクライアントとサーバ側の通信をするサンプルを試しました。
ここでは、クライアントから異なるサーバ(ドメイン)に対しての通信方法を試してみます。
異なるサーバ間の通信はJSONPを使用して行います。
具体的にはクライアントからサーバ側に通信を行う際に、単純にjavascriptの
データや、画面上のフォーム情報を送るのではなく、
データを整形したうえでコールバック関数の形にし、コールバック関数名とデータを送信します。
サーバ側では、受信したデータをもとに、指定の処理を行い、クライアント側に
コールバック関数名と、処理結果をセットで返します。
例えば、送信するデータが下記のようなjson形式のデータの場合
[{1:aaa},{2:bbb},{3:ccc}]
以下のようなコールバック関数名をつけた形にして送信します。
(関数名はあえてわかりやすく書いています)
callbackTestFunction([{1:aaa},{2:bbb},{3:ccc}])
この「callbackTestFunction」と書いたコールバック関数名が、サーバ側からの
値が返却され後のjavascript側で動作する関数名になります。
次にサーバ側の処理ですが、phpで以下のように返却します。
// 返却用のサンプルデータを用意
$result_arr = array(
"sample_value" => "test1",
"status" => "ok"
);
// ヘッダ情報を確定
header( 'Content-Type: text/javascript; charset=utf-8' );
// クライアント側にコールバック関数名と共にサンプルデータをjsonエンコードして返却する
echo "callbackTestFunction(" . json_encode($result_arr). ")";
のように書きます。
さらにクライアント側では、サーバ側から返却された値を処理する為に
callbackTestFunction用のコールバック関数を書き、その内部でサーバからの返却値を処理します。
実際に動作するHTMLを用意しました。
javascriptを含むHTML全体のソースです。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
</head>
<body>
<form id="testform" enctype="multipart/form-data">
<div>
<input type="text" name="text1" id="text1">
</div>
<div>
<input type="button" id="sample_file_upload" value="JSONPのテスト">
</div>
</form>
<div>通信時の処理内容</div>
<div id="ajax_result"></div>
<script type="text/javascript">
// ファイルアップロードボタンのDOMを取得
let element_sample_file_upload = document.getElementById('sample_file_upload');
element_sample_file_upload.addEventListener('click', SendXMLHttpRequest, false);
// 通信処理を画面に出力する為、操作用DOMの取得
let result = document.getElementById("ajax_result");
// ボタン押下時の処理
function SendXMLHttpRequest()
{
// 処理開始
result.innerHTML += 'ファイルアップロードのテスト start' + '<br />';
result.innerHTML += '通信処理の開始' + '<br />';
// フォーム内容の取得
let testform_data = document.getElementById("testform");
// 送信用データ
// フォーム内容を取得して、jsonpでの通信時のパラメータに付与する
// デモ画面は入力項目が一つなので、URLのパラメータに直接指定する
let form_data = new FormData(testform_data);
let params = "text1=" + form_data.get('text1');
// パラメータの全体を生成
let url_params = "?" + params + "&callback=callbackTestFunction";
// 同一出身ポリシーの制限があるので、スクリプトタグを生成して、外部サーバにアクセスする
let tag_script = document.createElement("script");
// ファイルタイプを指定する
tag_script.type = "text/javascript";
result.innerHTML += 'url_params -> ' + url_params + '<br />';
// 実行するサーバとは別のドメインを指定
tag_script.src = "https://propanlab.net/demo/blogsample/js/078/response.php" + url_params;
document.body.appendChild(tag_script);
result.innerHTML += '通信処理の終了' + '<br />';
}
// コールバック関数の処理
let callbackTestFunction = function(json)
{
console.log(json.sample_value);
console.log(json.status);
console.log(json.demp_param);
// 念のため画面にも出力
result.innerHTML += 'JSONPで取得した値の確認' + '<br />';
result.innerHTML += 'json.sample_value -> ' + json.sample_value + '<br />';
result.innerHTML += 'json.status -> ' + json.status + '<br />';
result.innerHTML += 'json.demp_param -> ' + json.demp_param + '<br />';
}
</script>
</body>
</html>
また、サーバ側のphpは以下のようにし、他ドメインのサーバ側に用意しました。
<?php
// コールバック関数名を取得し、そのまま返却時に使用
$demo_callback = $_GET["callback"];
// パラメータ「text1」の値をそのまま返す(デモ用なので)
$demo_param = $_GET["text1"];
// 返却用のサンプルデータを用意
$result_arr = array(
"demp_param" => $demo_param,
"sample_value" => "test1",
"status" => "ok"
);
// ヘッダ情報を確定(javascript指定にします)
header("Content-Type: text/javascript; charset=utf-8");
// クライアント側にコールバック関数名と共にサンプルデータをjsonエンコードして返却する
echo $demo_callback . "(" . json_encode($result_arr). ")";
?>
実際に画面にアクセスすると、まず次のようになります。

次に、テキストエリアにテスト文字列を入力します。

その後に、「JSONPのテスト」ボタンを押下します。

その際の開発者ツールの通信部分は次のようになります。
別ドメインにあるphpプログラムにアクセスし、結果が返り画面が更新されます。

通信部分のサーバからの返却結果を確認すると次のようになります。

また、画面上のHTMLは次のように更新されます。
javascript側で動的に「script」タグを生成しているので、
htmlに出力した部分が
src="https://propanlab.net/demo/blogsample/js/078/response.php?text1=1234&callback=callbackTestFunction
になり、
scriptタグで別サーバへ通信を行っていることがわかります。

ざっと試しましたが、本来の開発では値のチェックや
イレギュラーケースを考慮して実装する必要があります。