JSONPについて

javascript

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>

サーバ上のHTMLはこちら(test1.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&amp;callback=callbackTestFunction

になり、
scriptタグで別サーバへ通信を行っていることがわかります。

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

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です