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タグで別サーバへ通信を行っていることがわかります。
ざっと試しましたが、本来の開発では値のチェックや
イレギュラーケースを考慮して実装する必要があります。