Ajax
jQuery を使わない素の Javascript で AJAX を実装する方法については以下をご覧ください。
- AJAX XMLHttpRequest の基本的な使い方
- Fetch API の使い方
- WordPress で AJAX(基本的な使い方)
- WordPress AJAX で並べ替え(AJAX フィルターと追加読み込み)
作成日:2015年12月19日
Ajax (エイジャックス)とは
Ajax (エイジャックス)とは、Asynchronous JavaScript And XML の略で、非同期通信を利用してデータを取得したり、動的にウェブページの内容を書き換える技術のことです。
Ajax を使った代表的な例としては、地図アプリケーションの Google マップがあります。
今では当然ですが、Google マップではブラウザ上をマウスのドラッグによって地図の表示範囲を移動させたり,拡大/縮小率を変更したりできます。Ajax が出現る前までは,地図上の表示や縮小率を切り替えるたびに,その都度ページを切り替えなければなりませんでした。
Ajax では,ページ上でボタンがクリックされたりすることによって発生するイベントを JavaScript で捕捉し,必要な情報を XMLHttpRequest オブジェクト(HTTP通信を行うためのオブジェクト)を使ってサーバーに送信します。
サーバー側で処理された結果を非同期に受け取り,ページの必要な部分だけを動的に更新します。
「非同期に」とは,処理を行っている間,クライアント側の処理が中断されないこと(サーバーからの応答を待つ必要がないこと)です。つまり、サーバー側の処理とクライアント側での動作がそれぞれに別々に動作していることを意味します。
Ajax を利用すると、ページの一部だけを更新することができるため、Web ページの操作性を向上することができます。
Ajax の例
次のコードは、ボタンをクリックすると ajax_01.html というファイルを取得して、そのファイルから ajax_test という id を持つ div 要素を取り出し、それを ajax_test_sample という idを持つ div要素に表示するという動作を書いたものです。
$("#ajax_test_button").click(function() { var xhr; if(window.ActiveXObject){ xhr = new ActiveXObject("Microsoft.XMLHTTP"); } else if(window.XMLHttpRequest){ xhr = new XMLHttpRequest(); } else{ throw new Error("Ajax is not supported by this browser"); } xhr.onreadystatechange = function(){ if(this.readyState == 4){ if(this.status >= 200 && this.status < 300){ var div = this.responseText.match(/<div id="ajax_test">[\s\S]*<\/div>/g); $("#ajax_test_sample").html(div[0]); var style = this.responseText.match(/<style>[\s\S]*<\/style>/g); $("head").append(style); } } } xhr.open('GET', '../samples/ajax_01.html'); xhr.send(null); });
コードの内容を見てみます。
XHR インスタンスの生成
Ajax では、サーバとの通信を行うために JavaScript の XHR ( XMLHttpRequest )オブジェクトを介して非同期要求を発行しますが、ブラウザによって XHR の実装方法が異なるため、以下の部分ではブラウザに適した方法で(機能検出を使って) XHR インスタンスを生成しています。
//XHRのインスタンスを実体化するのに使われる機能検出を使ったイディオム var xhr; if(window.ActiveXObject){ //ActiveXが存在するかをテスト xhr = new ActiveXObject("Microsoft.XMLHTTP"); } else if(window.XMLHttpRequest){ //XHRが定義されているかをテスト xhr = new XMLHttpRequest(); } else{ //Ajaxのサポートがなければエラーを送出 throw new Error("Ajax is not supported by this browser"); }
上記で作成された XHR インスタンスは、以下のようなプロパティとメソッドを持っています。
メソッド | 説明 |
---|---|
abort() | 現在実行している要求をキャンセルする |
getAllResponseHeaders() | すべての応答ヘッダの名前と値を含む1個の文字列を返す |
getResponseHeader(name) | 名前を指定した応答ヘッダの値を返す |
open() パラメータ: method, url, async, username, password |
要求のHTTPメソッド(GETかPOST)と相手のURLを設定する。オプション async で、同期要求を指定できる。コンテナベースの認証が必要な要求のためにユーザ名とパスワードを提供できる |
send(content) | 要求の発行を開始する(オプションとして本文コンテンツを提供できる) |
setRequestHeader(name,value) | 指定の名前と値によって要求ヘッダを設定する |
プロパティ | 説明 |
onreadystatechange | 要求の状態が変化したときに呼び出されるイベントハンドラ |
readyState | アクティブな要求の現在の状態を示す整数値 0 = UNSENT 1 = OPENED 2 = HEADERS_RECEIVED 3 = LOADING 4 = DONE |
responseText | 応答で返された本文コンテンツ |
responseXML | 本文コンテンツがXMLと識別されたとき、その本文コンテンツから作成されたXML DOM |
status | サーバから返された応答ステータスコード。200は"success"、400は"not found"を表す。 (RFC 9110 | HTTP Semantics | Status Codes) 200から299までの範囲にあるステータスコードは全て成功で、300以上はさまざまな失敗を表す |
statusText | 応答で返されたステータスメッセージ |
要求の開始
サーバに要求を送信するには、以下のセットアップを実行する必要があります。
- HTTPメソッドを指定(POST、GETなど)
- 交信するサーバ側リソースのURLを提供
- XHRインスタンスに、進捗状況報告の手段を提供
- POST要求で本文コンテンツがあれば提供
最初の2つ(1, 2)は、XHRの open()メソッドを呼び出すことで設定します。
xhr.open('GET', 'url');
open メソッド
open メソッドはサーバに対する HTTP リクエストを作成します。
1番目の引数(method)にはリクエストが GET なのか POST なのかを指定します。(必須)
2番目の引数(url)にはリクエストを送るURLを指定します。(必須)
3番目の引数(async)には非同期通信か同期通信かを指定します。同期通信の場合は false を、非同期通信の場合は true を指定します。省略した場合は true(非同期通信)が設定されます。
レディステートハンドラ
3番目のステップでは、XHRオブジェクトの onreadystatechange プロパティに対してコールバック関数(レディステートハンドラ)を設定します。
レディステートハンドラを構築するには、XHRの onreadystatechange プロパティに、 レディステートハンドラにする関数への参照を割り当てます。
一旦、要求発行が開始されると、レディステートハンドラは要求のさまざまな進行状態で何度も呼び出されますが、多くの場合 DONE ステート(成功した場合)にのみ注目し、それ以外は無視するように書かれます。
xhr.onreadystatechange = function(){ if(this.readyState == 4){ //DONEステート以外は全て無視 //応答ステータスによって分岐 if(this.status >= 200 && this.status < 300){ //成功し場合に実効するコード } else{ //失敗時に実行するコード } } }
4番目のステップでは、POST要求に本文コンテンツがあれば提供し、サーバに送信します。
send メソッド
リクエストをサーバへ送信するには send メソッドを使います。
「POST」を使う場合には、サーバへ送るデータをここで指定します(名前と値を正しく URI エンコーディングする必要があります)。「GET」を使う場合には、通常は本文がないので(データは URL の後に記述して送られるので)引数には「null」を記述しておきます。
send(null);
応答の取得
レディステートハンドラが readyState を完了(DONE)と判定して要求が成功したら、XHR インスタンスから応答の本文を取り出すことができます。
応答本文は XHR インスタンスの responseText プロパティを介して取得できます。もし応答のコンテントタイプ(Content-Type)ヘッダが、text/xml か application/xml 、あるいは +xml で終わるMIMEタイプを示していたら、その応答本文のフォーマットはXMLと見なされ、コンテンツがXMLと解析され、 その結果の DOM が responceXML プロパティとなります。
そのあとは、JavaScript 及び jQuery を使って、そのXMLを処理できる。
以下に再度コードを掲載します。
var xhr; if(window.ActiveXObject){ xhr = new ActiveXObject("Microsoft.XMLHTTP"); } else if(window.XMLHttpRequest){ xhr = new XMLHttpRequest(); } else{ throw new Error("Ajax is not supported by this browser"); } xhr.onreadystatechange = function(){ if(this.readyState == 4){ if(this.status >= 200 && this.status < 300){ var div = this.responseText.match(/<div id="ajax_test">[\s\S]*<\/div>/g); $("#ajax_test_sample").html(div[0]); var style = this.responseText.match(/<style>[\s\S]*<\/style>/g); $("head").append(style); } } } xhr.open('GET', '../samples/ajax_01.html'); xhr.send(null);
jQuery を使うと、上記と同じことが load() メソッドを利用して以下のように記述できます。
$('#ajax_test_sample').load('../samples/ajax_01.html #ajax_test', function(response) { var style = response.match(/<style>[\s\S]*<\/style>/g)[0]; $("head").append(style); } );
上記のコードの詳細は style 要素の読み込みを参照ください。
Ajax 利用時の制限
Ajax にはいくつかの制限があります。
1.文字コードは、原則として「UTF-8 」
文字コードは、原則として「UTF-8 」しか使えません。(他の文字コードを使うと文字化けしてしまいます)
2.クロスドメインの制限
Ajax ではセキュリティ上の理由から、HTML と同一ドメイン上にあるファイルしか取得できません。
異なるドメイン上のファイルを取得する方法の1つは、PHP などのサーバーサイドプログラムを利用するの方法です。但し、その場合セキュリティに十分な配慮をしなければなりません。
自分の管理下にないサーバーのファイルを読み込む場合、不正に書き換えられたファイルをそのまま読み込んでしまう恐れがあるため大変危険なので注意が必要です。
例えば、PHP の場合、以下のようなスクリプトを作成し、Ajax を利用したい HTML と同一ドメインのサーバにアップロードします。
<?php $url = "読み込みたい他のドメインのURL"; $xml = file_get_contents($url); header("Content-type: application/xml; charset=UTF-8"); print $xml; ?>
上記のスクリプトは、指定した URL のファイルを読み込み、読み込んだ内容をそのまま出力します。
load() を使ってこの PHP ファイルを指定すれば、PHP ファイル自体は HTML と同一ドメインにあるため、他ドメインにあるファイルの内容を Ajax で取得できます。但し、そのファイルが安全であるということが前提になります。
コンテンツのロード load()
jQuery の load() メソッドは引数に読み込むファイルを指定すると、セレクタで指定した要素の内容を取得したデータで書き換えます。
言い換えると、指定した要素に読み込んだファイルのデータを挿入することができます。
以下が、その書式です。
$(selector).load(url, parameters, callback)
load() は指定の URL に向けて、 Ajax 要求の発行を開始します。そして成功したレスポンスであると判断した場合、マッチした要素全ての内容が、取得したデータで置き換えられます。
また、要求が完了して DOM の書き換えが完了したとき呼び出されるコールバック関数を指定することができます。
パラメータ
- url(String)
- 取得したい(読み込みたい)ファイルの URLを指定します。オプションとしてセレクタを使用することができます。
- parameters(String|Object|Array)オプション
- サーバー側への要求のパラメータとして渡すべきデータを指定できます。
★オブジェクトまたは配列で指定した場合、要求には POST メソッドが使用され、 省略した場合と文字列で指定した場合は、GET メソッドが使われます。
- callback(Function)オプション
- コールバック関数を指定します。この関数はマッチした要素(集合)に取得したデータが挿入された後に呼び出されます。
この関数に渡されるパラメータは、
・response:応答テキスト(取得したデータ)
・status:ステータス文字列(success、 error、notmodified、timeout、parsererror)
・xhr:XMLHttpRequest インスタンスです。
この関数はラップ集合内の各要素につき1回ずつ呼び出され、ターゲットの要素(集合)が関数のコンテクスト(this)となります。
- 戻り値
- ラップ集合
応答として返される要素にフィルタをかける
load() に単純に HTML ファイルを指定すると HTML ファイルの冒頭から末尾(<!DOCTYPE...から </html>まで)を取り込んでしまいます。 HTML の場合、 ファイル名の後ろに セレクタを指定することで、読み込む場所(要素)を絞り込むことができます。
セレクタを指定するには、URL の後に、1個のスペースに続けてセレクタを書きます。例えば、応答要素(取得するデータ)にフィルタをかけて div 要素だけを注入したい場合は、次のように書きます。
$('.injectToMe').load('en/schedule.html div');
例えば、以下のような HTML ファイル(../samples/ajax_02.html)の table 要素(table#schedule)の内容を取得してみます。
<body> <div id="container"> <div id="content"> <h1>Ajax sample table</h1> <p>This is a sample page for the ajax test</p> <h2>Schedule</h2> <div> <table id="schedule"> <tr> <th>DATE</th> <th>VENUE & LOCATION</th> <th>REMARK</th> </tr> <tr> <td class="date">3/26 (Wed.) </td> <td class="info"> 8-11pm <br> <span class="venue">The 76 House</span> <br> (110 Main St. Tappan, NY) </td> <td class="remark">No music charge<br> (845) 359-5476</td> </tr> <tr> <td class="date">4/5 (Sat.) </td> <td class="info"> 8-12 midnight <br> <span class="venue">Cleopatra's Needle</span> <br> (93 St. at Broadway)</td> <td class="remark">No music charge<br> (212) 769-6969 </td> </tr> ...... </table> </div> </div> </body>
単に load() の引数の URL にファイル名のみで ../samples/ajax_02.html と指定すると、そのページ全体を取得してしまいます。
table 要素のみを取得したい場合は、ファイル名の後にスペースに続けて、取得する要素のセレクタを指定します。
以下はボタンをクリックすると、ajax_02.html というファイルの table 要素を取得して、injectToMe というクラス名の div 要素に挿入して表示する例です。
<div id="jqs-1"> <div class="injectToMe"></div> <button>Load</button> </div>
$("#jqs-1 button").click(function() { $("#jqs-1 .injectToMe").load("../samples/ajax_02.html table#schedule"); });
今度はコールバック関数を使って、取得したデータを加工して表示してみます。
この例では ajax_02.html の <td class=”date”> と <span class=”venue”> を抽出して以下の HTML の injectToMe というクラス名の div 要素に挿入して表示します。
<div id="jqs-2"> <div class="injectToMe"></div> <button>Load</button> </div>
表示する際は、「class=”date”」の情報は dt 要素、「class=”venue”」の情報は dd 要素を使って表示します。以下がそのコードです。
$("#jqs-2 button").click(function() { $("#jqs-2 .injectToMe").load("../samples/ajax_02.html table#schedule", function(response, status, xhr) { var table$ = $(this); var date$ = table$.find('td.date'); var venue$ = table$.find('td.info span.venue'); var html = ""; for(var i = 0; i < date$.length; i ++) { html += "<dl><dt>" + date$.eq(i).text() + "</dt>\n<dd>" + venue$.eq(i).text() + "</dd></dl>"; } $(this).html(html); }); });
コールバック関数は、マッチした要素に取得したデータが挿入された後に呼び出されるので、$(this) にはすでに、table 要素 <table id="schedule">~</table> の jQuery オブジェクトが入っています。それをまず変数(table$)に格納します。
★コールバック関数に渡されるパラメータの response(取得したデータ)には、取得する要素をフィルタしても、常に GET でリクエストされた HTML 全体の文字列が入っています。(後述参照)
そして find() を使って、 <td class=”date”> と <span class=”venue”> の要素を抽出して、それらを変数(date$, venue$)に格納します。
変数 html は、 injectToMe というクラス名の div 要素に挿入する HTML で、まず空文字列で初期化しておきます。
for 文を使って、要素の数だけ繰り返し処理を行います。繰り返しの数は、date$.length または、venue$.length で取得できます。
繰り返し処理の中では、date$ 及び venue$ から eq() と text() を使ってそれぞれの要素のテキストを取得して、それを dt 及び dd 要素の内容として html に追加しています。
繰り返し処理が終了したら、全ての要素の内容を html に代入できているので、それを $(this) つまり、$("#jqs-2 .injectToMe") の HTML に設定します。
パラメータ response の内容
コールバック関数に渡されるパラメータ response(取得したデータ)は、少し誤解しやすい気がするので確認してみます。
load() の第1引数の URL に jQuery のセレクタを指定して、取得する要素をフィルタしても、コールバック関数に渡されるパラメータ「response:取得したデータ」は常に GET でリクエストされた HTML 全体(<!doctype html>~</html> )になっています。
以下のコードは、load() を実行した際に、コンソールにパラメータ response の内容と、$(this) の内容を表示ます。
$("#jqs-3 button").click(function() { $("#jqs-3 .injectToMe").load("../samples/ajax_02.html table#schedule", function(response) { console.log("response: " + response); console.log("$(this): " + $(this).html()); $(this).html("<p>F12キー を押して、コンソールの出力を確認してください。</p>"); }); });
以下のボタンをクリックして、コンソールに表示されるパラメータ response の内容と、$(this) の内容を表示して比較してみてください。
スクリプトのロード $.getScript()
以下のリンクのページのアニメーションの部分を load() を使って、ページに挿入する場合は、アニメーションの jQuery を記述したファイルも読み込まないとアニメーションが動きません。
また、その部分のスタイルも、指定されているスタイルシートを読み込まないとスタイルが反映されません。(予め読み込む側のページのスタイルシートに、そのスタイルを追加しておけば別ですが)
ajax_03.html <!doctype html> <html> <head> <meta charset="utf-8"> <title>Ajax sample Script</title> <link rel="stylesheet" href="ajs_03.css"> </head> <body> <div id="container"> <div id="content" class="clearfix"> <h1>Ajax sample Script</h1> <p>This is a sample page for the ajax test</p> <h2>Animation Sample for Ajax Test</h2> <div id="jqs-18" class="jqs_div"> <div class="yellowCircle"></div> <div class="blueCircle"></div> <p class="margin_top30"></p> </div> </div> <script src="https://code.jquery.com/jquery-1.11.3.min.js"></script> <script type="text/javascript" src="ajs_03.js"></script> </body> </html>
関数などが記述してある外部の JavaScript ファイルをロードするには、コールバック関数で $.getScript() を使って読み込むとができます。
$.getScript(url, callback);
url パラメータで指定されたスクリプトをサーバへの GET 要求を使って取得します。オプションとして成功時にコールバックを呼び出すことができます。
パラメータ
- url(String)
- 取得するスクリプトの URL。この URL は、ページと同じドメインに制限されません。
- callback (Function)
- オプションのコールバック関数を指定できます。スクリプトのリソースがロードされ、評価された後に呼び出されます。
このコールバック関数に渡されるパラメータは、以下になります。
・script (String) : ロードされたスクリプト
・textStatus (String) :テキストステータスメッセージ(成功すれ "success")
・jqXHR (Object) :jqXHR オブジェクト
- 戻り値
- スクリプトのフェッチに使用した XMLHttpRequest オブジェクト。
前述の ajax_03.html のアニメーションの部分(id="jqs-18")を以下のような HTML の div 要素(class="injectToMe")にロードしてみます。
<div id="jqs-4"> <div class="injectToMe"></div> <button> Load</button> </div>
4行目で、$.getScript()を使って、JavaScript(ajs_03.js)をロードしています。
$("#jqs-4 button").click(function() { $("#jqs-4 .injectToMe").load("../samples/ajax_03.html #jqs-18", function(response) { $.getScript('../samples/ajs_03.js'); $("head").append($("<link rel='stylesheet' type='text/css' href='../samples/ajs_03.css'>")); }); });
また、5行目では、append() を使って、CSS を追加して、スタイルを反映するようにしています。(後述)
以下のボタンをクリックすると、上記のコードを実行して、アニメーションの部分をロードします。
CSS のロード
外部の CSS を jQuery を使って、動的にロードする(読み込む)には以下のようにします。
$("head").append($("<link rel='stylesheet' type='text/css' href='CSS ファイルの URL'>"));
head 要素の末尾に append() を使って CSS の link 要素を追加しています。
何回も使用するならば、以下のように関数にしておくと便利かも知れません。
loadCSS() は引数に CSS の URL を受け取ります。
loadCSS = function(href) { var cssLink = $("<link rel='stylesheet' type='text/css' href='"+href+"'>"); $("head").append(cssLink); }; loadCSS("style.css");
この方法で JavaScript ファイルも動的にロードすることができます。以下はその例です。
この例では、body 要素の末尾に JavaScript ファイルを追加していますが、CSS と同様に head 要素の末尾に追加しても大丈夫です。
loadJS = function(src) { var jsLink = $("<script type='text/javascript' src='"+src+"'>"); $("body").append(jsLink); }; loadJS("one.js");
前述のサンプルをこれらの関数を使って書き換えると以下のようになります。
loadCSS = function(href) { var cssLink = $("<link rel='stylesheet' type='text/css' href='"+href+"'>"); $("head").append(cssLink); }; loadJS = function(src) { var jsLink = $("<script type='text/javascript' src='"+src+"'>"); $("body").append(jsLink); }; $("#jqs-5 button").click(function() { $("#jqs-5 .injectToMe").load("../samples/ajax_03.html #jqs-18", function(response) { loadCSS("../samples/ajs_03.css"); loadJS("../samples/ajs_03.js"); }); });
ボタンをクリックすると、前述のサンプルと同じ結果が得られます。
style 要素の読み込み
load() を使って外部の HTML ファイルをロードする際に、そのファイルに記述されている style 要素(<style>~</style>)を読み込む場合のサンプルです。
以下のように HTML ファイルに style 要素が記述されている場合を想定しています。
<!doctype html> <html lang="ja"> <head> <meta charset="utf-8"> <title>Ajax Test</title> <style> #ajax_test { width: 400px; border: 1px solid #CBC8C8; margin: 20px 0; padding: 10px; } #ajax_test p { text-align: center; color: #A49C9C; } #ajax_test img { border: 3px solid #AD94B8; } #sample_text { margin-top: 20px; } </style> </head> <body> <div id="ajax_test"> <p id="sample_text">This is for an Ajax Test.</p> <p><img src="../images/css/flower2.jpg" alt="Photo of a flower"></p> </div> </body> </html>
id="ajax_test" の div 要素を load() を使って読み込むには以下のように記述しますが、 style 要素に記述されているスタイルは、このままでは反映されません。
$('#ajax_test_sample').load('../samples/ajax_01.html #ajax_test');
以下のように、コールバック関数の中で、正規表現の match() を使って style 要素を取り出して、head 要素に append() を使って追加します。
$('#ajax_test_sample').load('../samples/ajax_01.html #ajax_test', function(response) { var style = response.match(/<style>[\s\S]*<\/style>/g)[0]; $("head").append(style); });
Ajax 要求の制御 $.ajax()
Ajax 要求を細かく制御したいときのために、汎用のユーティリティ関数 $.ajax() があります。Ajax 要求を発行する jQuery 機能は、どれも内部では この関数を使っています。
以下が、その書式です。
$.ajax(url,options)
渡されたオプションを使って Ajax 要求を開始します。オプションは、要求発行とコールバック通知を制御するのに指定します。
パラメータ
- url (String)
- 要求の URL。
- options (Object)
- プロパティによって処理のパラメータを定義するオブジェクト。詳細は次の表参照。
戻り値
XHRインスタンスを返します。※ jQuery 1.5 からは jQuery XMLHttpRequest (jqXHR) オブジェクトを返します。jqXHR は XMLHttpRequest オブジェクトのスーパーセットです。
次の表はオプションの定義で、重要な順に、また用途が近いものを並べてあります。オプションの詳細は api.jquery.com を参照してください(以下の情報は古くなっている可能性があります)。その他のオプションとして、 accepts, jsonpCallback, contents, converters, crossDomain, headers, statusCode, isLocal, mimetype, xhrFields などがあります。
名前 | 説明 |
---|---|
type | (String)使用するHTTPメソッド。通常はPOSTまたはGET。省略時のデフォルトはGET。 |
data | (String|Object|Array)要求に渡すクエリパラメータの役割を果たす値を定義する。もしGET要求なら、このデータはクエリ文字列として渡される。 POSTなら、データは要求本文として渡される。どちらの場合も、値のエンコーディングは $.ajax() ユーティリティ関数によって処理される。このパラメータは、(クエリ文字列または要求本文として使われる)文字列か、(プロパティがシリアライズされる)オブジェクトか、(name 及び value プロパティが名前と値のペアを指定する)オブジェクトの配列。 |
dataType | (String)サーバーから返されると予想されるレスポンスのデータのタイプ。何も指定されていない場合、jQuery はレスポンスの MIME タイプに基づいてそれを推論しようとします (XML MIME タイプは XML を生成し、 JSON は JavaScript オブジェクトを生成し、script はスクリプトを実行します。その他はすべて 文字列として返されます)。以下が指定可能なタイプです。
|
cache | (Boolean)もしfalseなら、応答がブラウザによってキャッシュされないようにする。デフォルトは true(但し dataType が script または jsonp の場合を除く) |
context | (Element)この要求に関連するすべてのコールバックにコンテクストとしてして設定する要素を指定する。 |
timeout | (Number)Ajax 要求のタイムアウトをミリ秒単位で設定する。もし要求が完了する前にタイムアウトしたら、その要求はアボートされ、(もし定義されていたら)エラーコールバックが呼び出される。 |
global | (Boolean)もし false なら、Ajax グローバルイベントのトリガを禁止する(これは Ajax 要求の処理中にさまざまなポイントあるいは条件によってトリガされる jQuery 独自のカスタムイベント)。もし省略されたら、デフォルトの true となり、グローバルイベントのトリガが許可される。 |
contentType | (String)要求で指定するコンテントタイプ。もし省略したら、デフォルトは、application/x-www-form-urlencodedとなる。これは、フォーム送信でデフォルトとして使われるものと同じ。 |
success | (Function)要求への応答が成功のステータスコードを示したときに呼び出される関数を指定。応答本文が、この関数への第1パラメータとして渡され、dataType プロパティの指定に従って評価される。第2パラメータはステータス値を含む文字列で、この場合は常に"success"である。第3パラメータは、XHR(jQuery1.5からはjqXHR)インスタンスへの参照を提供する。jQuery1.5 からは、順番に実行される複数の successコールバックを配列で渡すことができる。下記の error、complete も同様。※ |
error | (Function)要求への応答がエラーのステータスコードを示したときに呼び出される関数。これには3つの引数が渡される:jQuery1.5からはjqXHRインスタンス(この場合はエラーを表すオブジェクト)、ステータス値を含む文字列("error", "timeout", "notmodified", "parseerror"のどれか)、及びオプションの例外オブジェクト。 ※ |
complete | (Function)要求の完了時に呼び出される関数。これには2つの引数が渡される。XHR(jQuery1.5からはjqXHR)インスタンスと(success、error などの)ステータスメッセージ文字列。もし errorや successのコールバックも同時に指定されていたら、それらが呼び出されたあとに、このコールバックが呼び出される。※ |
beforeSend | (Function)要求を発行する前に呼び出される関数。この関数には、XHR(jQuery1.5からはjqXHR)インスタンスが渡され、カスタムヘッダの設定など要求の前処理を実行できる。このハンドラから falseを返したら要求はキャンセルされる。 |
async | (Boolean) falseが指定されたら、同期要求として送信される。デフォルトは非同期要求。 |
processData | (Boolean)もし falseに設定されたら、渡されたデータをURLエンコーディングされたフォーマットに変換する処理を行わない。デフォルトでは、データは application/x-www-form-urlencoded タイプの要求で使うのに適したフォーマットに URL エンコーディングされる。 |
dataFilter | (Function)応答データのフィルタリングのために呼び出される関数。この関数には、受け取ったままの応答データと datatType 値が渡される。この関数は「サニタイズ」したデータを返すことが求められる。 |
ifModified | (Boolean)もし trueなら、前回の要求と比べて応答内容が変化した場合のみ要求を成功と認める。この判定は、Last-Modified ヘッダによる。省略したら、ヘッダのチェックは行わない(デフォルトの false)。 |
jsonp | (String)jsonp要求のデフォルトコールバック関数名をオーバーライドするクエリパラメータ名を指定する。 |
username | (String) HTTP のアクセス認証要求に対して使用するユーザー名を指定する。 |
password | (String) HTTP のアクセス認証要求に対して使用するパスワードを指定する。 |
scriptCharset | (String)リモートコンテントとローカルコンテントで文字列集合が異なる場合、script及び jsonpタイプの要求で使用する文字列を指定する。 |
xhr | (Function)XHR インスタンスのカスタム実装を提供するのに使用するコールバック。 |
traditional | (Boolean)もし true なら、パラメータのシリアライゼーションに traditional スタイルを使用する。 |
サンプル
jQuery $.ajax() でフォームデータを ajax_form_test.php に送信する簡単なサンプルです。
<form id="ajax_form" type="get" action="../samples/PHP/ajax_form_test.php"> <input type="text" name="text" value="" /> <input type="submit" value="送信" /> </form> <p id="ajax_form_res" class="margin_top40"></p> <p id="ajax_complete"></p>
$('#ajax_form').submit(function(event){ event.preventDefault(); var form$ = $(this); $.ajax({ url: form$.prop('action'), type: form$.prop('method'), data: form$.serialize(), timeout: 1000, dataType: 'text', success: function(response) { //通信成功時の処理 //サーバからの出力本文はresponseに入る $('#ajax_form_res').text(response); }, error: function(error) { //通信失敗時の処理 $('#ajax_form_res').text(`失敗 ${error.status} : ${error.statusText}`); }, complete: function(xhr, msg) { // 通信完了時の処理 $('#ajax_complete').text(msg); } }) });
- .submit()
- form の submit イベントを利用します。
- event.preventDefault()
- 送信ボタンによるフォーム送信処理をキャンセルします。
- var form$ = $(this)
- フォーム要素を変数(form$)に格納
- url: form$.prop('action')
- URL(リクエスト先)を form 要素の action 属性から取得
- type: form$.prop('method')
- type(使用するHTTPメソッド)を form 要素の method 属性から取得
- data: form$.serialize()
- 送信するフォームデータを serialize() を利用してクエリ文字列を作成
- timeout: 1000
- タイムアウトを設定
- dataType: 'text'
- データのタイプを指定
- success: function(response)
- 通信が成功したときの処理を記述します。サーバからの出力本文は response に入っています。
※jQuery3.0 からこの関数は削除されました。(訂正)削除されたのは success() メソッドで success オプションではありません。このオプションは現在も問題なく使用することができます。
- error: function(xhr)
- 通信が失敗(エラー)したときの処理を記述します。
※jQuery3.0 からこの関数は削除されました。(訂正)削除されたのは error() メソッドで error オプションではありません。このオプションは現在も問題なく使用することができます。
- complete: function(xhr, msg)
- 通信完了時の処理の処理を記述します。
※jQuery3.0 からこの関数は削除されました。(訂正)削除されたのは complete() メソッドで complete オプションではありません。このオプションは現在も問題なく使用することができます。
誤解と混乱と訂正
jQuery.ajax() から返される jqXHR オブジェクトは jQuery Deferred で、これまでは、success、error、complete の引数オブジェクトに一致する名前を持つ 3 つのメソッド jqXHR.success(), jqXHR.error(), and jqXHR.complete() がありましたが、これらが削除されました。
success、 error、complete オプション(local callback event)は現在も使用することができ、非推奨にもなっていませんし、削除もされていません。
success, error, complete の代わりに done(), fail(), always() を使う例
オプションの success, error, complete(local callback event)の代わりに jqXHR オブジェクトのメソッド done(), fail(), always() を使って以下のように記述することもできます。
$('#ajax_form').submit(function(event){ event.preventDefault(); var form$ = $(this); $.ajax({ url: form$.prop('action'), type: form$.prop('method'), data: form$.serialize(), timeout: 1000, dataType: 'text' }) .done(function(response) { //通信成功時の処理 $('#ajax_form_res').text(response); }) .fail(function(error) { //通信失敗時の処理 $('#ajax_form_res').text( `失敗 ${error.status} : ${error.statusText}` ); }) .always(function(xhr, msg) { // 通信完了時の処理 $('#ajax_complete').text(msg); }); });
ajax_form_test.php
<?php //入力値に不正なデータがないかなどをチェックする関数 function checkInput($var){ if(is_array($var)){ return array_map('checkInput', $var); }else{ /*PHP 7.4.x で get_magic_quotes_gpc が非推奨になったので削除 //php.iniでmagic_quotes_gpcが「on」の場合の対策 if(get_magic_quotes_gpc()){ $var = stripslashes($var); }*/ //NULLバイト攻撃対策 if(preg_match('/\0/', $var)){ die('不正な入力です。'); } //文字エンコードのチェック if(!mb_check_encoding($var, 'UTF-8')){ die('不正な入力です。'); } //改行、タブを含む制御文字と文字数(100)のチェック if(preg_match('/\A[[:^cntrl:]]{0,100}\z/u', $var) === 0){ die('セキュリティのため100文字以下でお願いします。また、制御文字は使用できません。'); } return $var; } } //GETされたデータをチェック $_GET = checkInput($_GET); //GET 送信されたデータを受け取る $text = $_GET['text']; //ヘッダーの設定 header('Content-type:text/plain; charset=utf8'); //データをエスケープ処理して出力 echo htmlspecialchars($text, ENT_QUOTES, 'UTF-8'); ?>
jQuery.Deferred
jQuery.Deferred は jQuery のバージョン1.5から導入された、非同期処理を扱うためのモジュール(オブジェクト)です。
jQuery.Deferred では、非同期の処理に Promise オブジェクトを割り当て、そのオブジェクトの状態を伝播させていくことで処理を進めます。
ajax() メソッドから返される jqXHR オブジェクトは jQuery Deferred Object なので、Promise のような then() メソッドなどが使用できます。
then()
ajax() メソッドの戻り値は Deferred オブジェクトなので deferred.then() メソッドを使えます。
then() メソッドは Deferred オブジェクトが解決(resolved)された時、拒否(rejected)された時、または進行中(in progress)の時に呼び出されるハンドラー(コールバック関数)を追加します。
以下が書式です。
deferred.then( doneFilter [, failFilter ] [, progressFilter ] )
パラメータ | 説明 |
---|---|
doneFilter | Deferred オブジェクトが解決(resolved)された時(通信成功時)に呼び出されるコールバック関数。引数にレスポンスを受け取ります。 |
failFilter | Deferred オブジェクトが拒否(rejected)された時(通信失敗時)に呼び出されるコールバック関数。引数にエラーオブジェクトを受け取ります。オプション(省略可能) |
progressFilter | Deferred オブジェクトが進行中(in progress)の時に呼び出されるコールバック関数。オプション(省略可能) |
以下は使用例です。
ファイルが取得できた場合は、「succeeded: 」に続けてレスポンスのテキストをコンソールに出力し、失敗した場合は「failed!」に続けてエラーステータスとステータステキストを出力します。
$.ajax({ url: 'sample.txt', type: 'GET', dataType: 'text' }).then( // doneFilter function(data) { // 通信成功時 console.log( 'succeeded: ' + data ); }, // failFilte function(error) { // 通信失敗時 console.log( `failed! ${error.status} : ${error.statusText}` ); } );
アロー関数を使って以下のように記述することもできます。
$.ajax({ url: 'sample.txt', type: 'GET', dataType: 'text' }).then( // 通信成功時 data => console.log( "succeeded: " + data ), // 通信失敗時 error => console.log( `failed! ${error.status} : ${error.statusText}` ) );
また、前述の done() と fail() メソッドを使って以下のように書き換えても同じ結果になります。
$.ajax({ url: 'sample.txt', type: 'GET', dataType: 'text' }) .done(function(response) { //通信成功時の処理 console.log( 'succeeded: ' + response ); }) .fail(function(error) { //通信失敗時の処理 console.log( `failed! ${error.status} : ${error.statusText}` ); })
フォームデータのシリアライズ
ユーザがコントロールに入力したデータを集め、要求パラメータとして送信したいときは、serialize() メソッドでクエリ文字列を構築することができます。
serialize() メソッド
- serialize()
- ラップ集合の中にある(あるいは、ラップ集合に含まれるフォームの中にある)、全ての適格なフォーム要素から、適切にフォーマットされ、エンコーディングされたクエリ文字列を作成します。
パラメータ
なし
戻り値
フォーマットされたクエリ文字列
serialize() メソッドは、ラップ集合の中にあるフォームコントロールだけから情報を収集し、しかも適格と見なされた要素のみを対象とします。
適格なコントロールとは、HTML 仕様書のルールに従って、フォーム送信の一部に含められるもののことです。チェックされていないチェックボックスやラジオボタン、 選択されていないドロップダウンリスト、禁止されているコントロールは、適格と見なされず、フォームの送信に含まれないので、serialize() はこれらを無視します。
以下は、serialize() メソッドを使ってフォームのデータをシリアライズして表示させる例です。値を入力して「Submit」ボタンをクリックするとフォームのデータが適切にフォーマットされ、エンコーディングされたクエリ文字列になっているのがわかります。
$('#form_serialize').submit(function(event){ event.preventDefault(); var form$ = $(this); var data = form$.serialize(); $('#serialize_data').text(data); });
<form action="" method="get" id="form_serialize" class="form_sample"> <p>Name: <br> <input type="text" name="yourname" id="yourname" value="" size="20" placeholder=" Name"> </p> <p>E-mail: <br> <input type="text" name="youremail" id="youremail" value="" size="20" placeholder=" E-mail"> </p> <p>Gender: <br> <input type="radio" name="gender" value="male"> Male <input type="radio" name="gender" value="female"> Female </p> <p> <input type="submit" value="Submit"> <input type="reset" value="Reset"> </p> </form> <p>シリアライズされた値:<span id="serialize_data"></span></p>
シリアライズされた値:
serializeArray() メソッド
フォームデータを(クエリ文字列ではなく)、JavaScript 配列に入れたい場合は serializeArray()を使用します。
- serializeArray()
- 全ての適格なフォームコントロールの値をコントロールの名前と値を含むオブジェクトの配列に収集します。
パラメータ
なし
戻り値
フォームデータの配列
serializeArray() が返す配列は、それぞれ name プロパティと value プロパティを1個ずつ含む匿名のオブジェクトインスタンスで構成されます。 これは load() メソッドに対して要求パラメータのデータを渡すのに適したフォーマットになっています。
HTTP 通信
Web サーバーと Web クライアントが通信を行うには、どのような情報をやり取りするかとう取り決めが必要で、この取り決めを「通信プロトコル」と呼びます。
Web サーバーと Web クライアント(ブラウザ)がデータ(HTML等)をやり取り(送受信)するときに使うプロトコル(取り決め)を HTTP(Hyper Text Transfer Protocol)と言います。
GET と POST はブラウザがサーバーに対して要求(HTTP リクエスト)を送る際の一般的なメソッドです。
例えば、リンクを辿ったりアドレス欄に URL を入力したりして HTML ページを呼び出す場合、ブラウザは GET を使ってサーバーにファイルを要求します。
例えば、www.webdesignleaves.com/ というファイルを開く場合は、以下のようなリクエストが送信されます。
これらの内容を確認するには、ブラウザの F12 キーを押して、ネット(Network)のタブで確認することができます。
関連ページ:HTTP(PHP)
GET メソッド
GET メソッドの特徴は以下の通りです。
- リクエスト URL の後にパラメータを付けてデータを送付します。
- そのため、URL を見ると、入力したデータが見えてしまいます。(パスワード等の情報の扱いには向いていません)
- 送信できるデータ量(文字数)に制限があります。
- テキストデータのみ送信可能です。
Google で検索するときに、表示されるアドレスバーの内容は GET のリクエストです。
通常の URL の後に ? マークがあり、その後に & を含む文字列が続いています。? マーク以降を「クエリ文字列」と呼びます。
クエリ文字列の中は、& で区切られていて、それぞれの部分は「パラメータ = 値」という形式になっています。
POST メソッド
POST メソッドの特徴は以下の通りです。
- POSTの場合は、URL にはデータの内容は書き込まれず、HTTPリクエストのメッセージ・ボディという場所にデータが入って送信されます。
- テキストデータでもバイナリデータでも送信できます
- データ量が多くても大丈夫です。
GET と POST の違い
以下のような違いがあります。
- GET のレスポンスはキャッシュされますが POST はキャッシュされません(ブラウザ、プロキシ、ゲートウェイ等)。
- GET は URL にデータが載るので、Webサーバやプロキシサーバーのログに残ります。
- GET は URL をブックマーク保存できます(Googleの検索等)。
- GET は POST より送信できる情報量が少ない。
GET と POST の使い分け
GET
GET は何かを GET する(取得する)のが本来の役割です。単純にキーワード等を送って検索結果を「取り出す」ため等に使用します。
GET 要求は、単にデータを GET する(取得する)目的で要求を発行する場合に使うべきとされています。 GET でも何かのパラメータをサーバーに送る必要があるかもしれないけれど、何らかの変化をもたらすためにサーバーへデータを送るときは、POST を使用するべきです。
GET を使った場合、その結果はクライアントのディスクにキャッシュされ、次回以降はそのキャッシュの内容を利用することが期待されているので、(少なくとも短期的には)同じクエリによるリクエストに対しては同じ結果を返さなければならないことになっています。
つまり、同じ GET 処理を何度繰り返し行っても、まったく同じ結果が返されることが期待されます。(何らかの理由で、サーバーの状態が変化する場合を除いて)
また、GET はクエリが URI の一部になるため、それがそのままブックマークされたり、リンク先として用いられることがあります。
POST
POST は「投稿する」という意味です。メッセージの書き込み、新規データの登録など、何かをプログラムに送って内容を書き換えるような場合には POST を使わなければなりません。
POST 要求は、サーバーにデータを送ることで、アプリケーションモデルの状態を変化させることが可能であるということになります。
例えば、データベース内のレコードを追加あるいは更新したり、サーバーにある情報を削除するような処理がこれにあたります。