Analog Studio

Javascriptでページ遷移せずにPOST送信する方法【非同期通信】【XHR】

概要

データを POST メソッドでサーバなどへ送信する時、HTML の <FORM> 要素を使って送信するとページが遷移しますよね。
でも、場合によってはページ遷移はさせたくないけどデータは POST で送信したいということがあります。

今回は、そんな場合にどのようにすれば良いかをまとめます。
使う手法は、XMLHttpRequest (略して XHR ) という非同期でサーバとブラウザが通信を行う仕組みを利用してます。

フォームに入れたデータを送信する場合とデータは別で用意する場合の2パターンについて解説します。

POSTってなに?

POST メソッドというのは、HTTP リクエストでデータを送受信する方法の一つです。
送受信するデータはアドレスバーなどには表示されず、画像などのバイナリデータも扱うことができます。

データを見られたくない場合や大容量のデータ、バイナリデータなどを扱うのに適しています。

アドレスバーにデータが表示される GET メソッドも良く使われ、アドレスの "?" 以降に "データ名=データ値(&データ名=データ値…)" というように簡単にデータを見ることができる方式です。
最近のブラウザでは "?" 以降を自動的に表示しないようになっていることが多いので、目にしないことも増えています。
(但し、アドレスバーを選択すれば GET データは見ることができます)

ここから分かる通り、GET でのデータはアドレスの "?" 以降につけることで簡単に扱うことができ、気軽に使うことができます。
一方 POST は、データを送受信する仕組みを組む必要があります。
ちなみに、HTML の <FORM> 要素を使えば、簡単に POST 送信をことができます 。が、データ送信にはページ遷移を伴います。

Google 検索では見られても困ることはないので GET で検索語などの情報を扱っています。

Google検索はGETを使っています。

もう少し詳しくまとめた記事が Qiita さんのサイトにあるので、興味のある方はこちらもご確認下さい。
 ・Qiita - HTTPとPOSTとGET

XHR通信をする方法

XHRとは?

XHR とは XMLHttpRequest の略で、サーバとブラウザ間でのデータのやり取りを非同期、つまりページが読み込まれた後の任意のタイミングでデータのリクエストを行えるというものです。
これによりページの遷移無しに新たなデータをサーバから読み込んだりできます。便利ですね。

最初からページ内の要素を全て読み込んでも良いのですが、一度に大量のデータを読み込むと時間が掛かる上にスクロールされなかった (表示されない) 要素のリソースはムダになってしまうので、XHR などを用いて非同期で少しずつ読み込む方が良いです。
早く表示されるページはユーザにも Google にも好まれますのでアクセスUPにも繋がります。
軽量なサイトやページを構築したい方には必須の技術です。

XHRの基本の使い方

XHR による通信には専用のオブジェクト (XHR の通信を行うための手段が色々格納されているもの) が用意されています。
そのため、以下のように簡単に実行することが可能です。

// new演算子でXHRオブジェクトの実体を生成します // 変数名は任意に指定できます var XHR = new XMLHttpRequest(); // .open()メソッドで"どんな方式"で"どんなアドレス"に"非同期にするか"をしていします // 第3引数に"false"を渡すと同期通信となり、.send()以降はレスポンスが返ってくるまで実行されません // ("true"で非同期通信にすればレスポンスが返ってこなくても.send()以降が実行されます) XHR.open("POST", "./hoge/fuga.php", true); // 変数postDataに格納されたデータを送信します // GETなどで不要な場合は"null"を入れます // XHR.send(null); XHR.send(postData);

たったこれだけで XHR による通信が実現できます。

ページのソースファイルを取得してみる

では、実際に XHR でのデータ取得を見てみましょう。
まずは簡単にこのサイトの TOP ページのソースファイルを取得します。

ソースファイルを取得するには、GET でサーバにリクエストを投げればレスポンスとしてソースファイルが取得できます。
但し、HTTP サーバのレスポンスになるので PHP などのサーバ側での処理は完了して結果の HTML となります。
(PHP 等の実行ファイルを取得したい場合は、中身を文字列として返すような PHP を作成してそこにリクエストすれば取得できます)

<Javascript> var getSourceFile = function($URL){ // XHRの宣言 var XHR = new XMLHttpRequest(); // TOPページ($URL = https://web.analogstd.com/)にGETでリクエストする XHR.open("GET", $URL, true); // ブラウザからサーバへ送る情報は不要なのでnullを指定する; XHR.send(null); // サーバの応答をonreadystatechangeイベントで検出して正常終了したらデータを取得する XHR.onreadystatechange = function(){ if(XHR.readyState == 4 && XHR.status == 200){ document.getElementById("source_topPage").value = XHR.responseText; } }; } // ページ読込完了後にボタンにclickイベントを登録する window.addEventListener("load", function(){ document.getElementById("getSourceRun").addEventListener("click", function(){ // クリックしたらソースを取得しに行く getSourceFile("https://web.analogstd.com/"); }, false); }, false); <HTML> <button type="button" id="getSourceRun">ソースファイル取得</button> <textarea id="source_topPage" style="width:95%;height:400px;" placeholder="ここにソースが表示されます"></textarea>


このようにして簡単にソースファイルの取得ができました。

XHR の状態を表す "XHR.readyState" が "4" に変わったタイミングで処理が完了したことを表します。レスポンスの取得に成功したかはここでは分かりません。
readyState の値がそれぞれなにを表すかは、以下ページをご確認下さい。
 ・MDN Web Docs - XMLHttpRequest.readyState

同様に "XHR.status" はHTTPのリクエストに対するレスポンスを返します。
この値が "200" で正常な応答ができたことを表します。良く目にするのは500番台のサーバエラーです。
こちらも詳しくは以下をご確認下さい。
 ・MDN Web Docs - XMLHttpRequest.status
 ・MDN Web Docs - HTTP レスポンス状態コード

XHRを使ってPOSTでデータを送信する方法

ようやく本題です。
XHR を使って POST でデータを送信してみましょう。

HTML の <FORM> 要素を使う方法と使わない方法の2つについて解説します。
やはりフォームを使う方が簡単にデータを送信することができます。

HTMLフォームのデータを使う場合

フォームに入力されているデータを使う場合は、以下のようにして簡単にデータをセットすることができます。
FormData オブジェクトを使うことで簡単なコードで実現することができます。

<Javascript> // ページ読込完了後にボタンにclickイベントを登録する window.addEventListener("load", function(){ document.getElementById("send_userinfo").addEventListener("click", function(){ // FoemDataオブジェクトを実体化する際にHTMLフォームのセレクタを渡せば // データのキーと値をセットで準備することができます var formDatas = document.getElementById("userinfo"); var postDatas = new FormData(formDatas); // XHRの宣言 var XHR = new XMLHttpRequest(); // openメソッドにPOSTを指定して送信先のURLを指定します XHR.open("POST", "./hoge/fuga.php", true); // sendメソッドにデータを渡して送信を実行する XHR.send(postDatas); // サーバの応答をonreadystatechangeイベントで検出して正常終了したらデータを取得する XHR.onreadystatechange = function(){ if(XHR.readyState == 4 && XHR.status == 200){ // POST送信した結果を表示する document.getElementById("userinfo_response").innerHTML = XHR.responseText; } }; } ,false); }, false); <HTML> <form id="userinfo"> <p> <label for="item1">名前</label> <input name="name" id="item1"> </p> <p> <label for="item2">年齢</label> <input name="old" id="item2"> </p> <p> <label for="item3">住所</label> <input name="address" id="item3"> </p> </form> <p> <button type="button" id="send_userinfo">送信</button> </p> <div id="userinfo_response"> <!-- 結果を出力する --> </div>

POST によるデータ送信なので <input type="file"> のようなファイル選択要素を利用すればローカルファイルの送信にも対応します。
これにより画面遷移しない画像のアップローダを作成することなどに応用できます。

HTMLフォームを使わない場合

フォームを使わない場合でも FormData オブジェクトを使うことで POST 送信ができます。

<Javascript> // ページ読込完了後にボタンにclickイベントを登録する window.addEventListener("load", function(){ document.getElementById("send_fixdata").addEventListener("click", function(){ // FoemDataオブジェクトに要素セレクタ(引数)を渡さずに宣言する var fixedDatas = new FormData(); // appendメソッドでキーとデータの組をセットする // append("キー(FORMで云うところのname属性値)", "データ")でデータをセットできる fixedDatas.append("filename", "test.txt"); fixedDatas.append("filesize", "10,154B"); // XHRの宣言 var XHR = new XMLHttpRequest(); // openメソッドにPOSTを指定して送信先のURLを指定します XHR.open("POST", "./hoge/fuga.php", true); // sendメソッドにデータを渡して送信を実行する XHR.send(fixedDatas); // サーバの応答をonreadystatechangeイベントで検出して正常終了したらデータを取得する XHR.onreadystatechange = function(){ if(XHR.readyState == 4 && XHR.status == 200){ // POST送信した結果を表示する document.getElementById("fixdata_response").innerHTML = XHR.responseText; } }; } ,false); }, false); <HTML> <p> <button type="button" id="send_fixdata">固定データを送信する</button> </p> <div id="fixdata_response"> <!-- 結果を出力する --> </div>

HTMLフォームのデータにJavascriptでデータを追加して送信する場合

上記を組み合わせて使用することもできます。
<input type="hidden"> 要素を使用しなくても送信するデータを増やすことができます。

<Javascript> // ページ読込完了後にボタンにclickイベントを登録する window.addEventListener("load", function(){ document.getElementById("send_mixdata").addEventListener("click", function(){ // FoemDataオブジェクトに要素セレクタを渡して宣言する var formDatas = document.getElementById("userinfo2"); var mixedDatas = new FormData(formDatas); // appendメソッドでキーとデータの組をセットする // append("キー(FORMで云うところのname属性値)", "データ")でデータをセットできる // appendではデータは追加となる mixedDatas.append("filename", "test.txt"); mixedDatas.append("filesize", "10,154B"); // XHRの宣言 var XHR = new XMLHttpRequest(); // openメソッドにPOSTを指定して送信先のURLを指定します XHR.open("POST", "./hoge/fuga.php", true); // sendメソッドにデータを渡して送信を実行する XHR.send(mixedDatas); // サーバの応答をonreadystatechangeイベントで検出して正常終了したらデータを取得する XHR.onreadystatechange = function(){ if(XHR.readyState == 4 && XHR.status == 200){ // POST送信した結果を表示する document.getElementById("mixdata_response").innerHTML = XHR.responseText; } }; } ,false); }, false); <HTML> <form id="userinfo2"> <p> <label for="item1">名前</label> <input name="name" id="item1"> </p> <p> <label for="item2">年齢</label> <input name="old" id="item2"> </p> <p> <label for="item3">住所</label> <input name="address" id="item3"> </p> </form> <p> <button type="button" id="send_mixdata">入力値と固定値を送信する</button> </p> <div id="mixdata_response"> <!-- 結果を出力する --> </div>

まとめ

以上、XHR を利用したページ遷移を伴わない POST データ送信についてまとめました。
ページ遷移させたくないけど POST したいといった場合に参考にしてみて下さい。