前回は,従来型のPHPアプリケーションとAjaxアプリケーションを比較することで,Ajaxアプリケーションが従来型アプリケーションのどのような点を改善するものなのかを概観しました。今回は,前回紹介したコードを詳しく見ていくことにします。

 本連載のテーマであるAjaxという意味で注目する必要があるのは,クライアント側のコード(リスト1)です。サーバーサイド・アプリケーション(searchAjax.php)は前回見たように,クライアントから受け取ったISBNコードに基づいて対応する書名を出力するだけのごくシンプルなプログラムなので説明は省略します。

リスト1●AjaxアプリケーションのHTMLファイル(searchAjax.html)
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>書籍検索</title>
<script language="JavaScript">
<!--
 // [送信]ボタンをクリック時の処理を定義
 function send() {
   // 非同期通信を行うためのXMLHttpRequestオブジェクトを生成
  try {
    xmlReq = new ActiveXObject("Microsoft.XMLHTTP");
  } catch(e) {
    xmlReq = new XMLHttpRequest();
  }
   // サーバーからの応答時の処理を定義(結果のページへの反映)
  xmlReq.onreadystatechange = function() {
     var msg = document.getElementById("result");
     if (xmlReq.readyState == 4) {
      if (xmlReq.status == 200) {
        msg.innerHTML = xmlReq.responseText;
      } else {
        msg.innerHTML = "通信に失敗しました。";
      }
    } else {
      msg.innerHTML = "通信中…";
    }
  }
  
   // サーバーとの通信を開始
  xmlReq.open("GET","searchAjax.php?isbn="
                    + encodeURI(document.fm.isbn.value),true);
  xmlReq.send(null);
 }
//-->
</script>
</head>
<body>
<form name="fm">
ISBNコード:
<input type="text" name="isbn" size="30" />
<input type="button" value="送信" onclick="send()" />
<div id="result" />
</form>
</body>
</html>

クライアント側のイベントを捕捉して処理を起動

 Ajaxの処理が起動するきっかけになるイベント(event)とは,ユーザーのアクション,またはブラウザの動作によって発生する「できごと」のことです。クライアントサイド・スクリプト(JavaScript)では,ページ上で発生したイベントをトリガー(trigger=きっかけ)にして処理を起動するイベントドリブン(イベント駆動型)モデルを採用しています。

 JavaScriptで利用可能な主なイベントを,表1に挙げます(ただし,ブラウザの種類やバージョンによって認識できないイベントもあります)。リスト1では,[送信]ボタンがクリックされたタイミング(onclickイベントの発生タイミング)でJavaScriptのsend関数を呼び出し,サーバーとの非同期通信を開始しているというわけです(リスト1の下から5行目)。

表1●JavaScriptで利用可能な主なイベント
イベント名
発生するタイミング
onblur 要素からフォーカスが外れた
onchange 要素の内容が変更された
onclick

要素をクリックした
ondblclick 要素をダブルクリックした
onfocus 要素にフォーカスがあたった
onkeydown 何らかのキーを押下した
onkeyup キーボード上のキーを離した
onload ページがロードされた
onmousedown マウスのボタンを押した
onmousemove マウス・ポインタを移動した
onmouseout マウス・ポインタが要素から外れた
onmouseover マウス・ポインタが要素に乗った
onmouseup マウスボタンを離した
onreset フォームがリセットされた
onselect テキストが選択された
onsubmit フォームがサブミットされた
onunload ページがアンロードされた

非同期通信を管理する XMLHttpRequestオブジェクトを生成する

 サーバー側との非同期通信を管理するのは,XMLHttpRequestオブジェクトの役割です。XMLHttpRequestオブジェクトを利用することで,これまでブラウザが行ってきたHTTP通信の部分をJavaScriptで制御できるようになります。

 XMLHttpRequestオブジェクトは,多くのブラウザで以前から提供されてきたオブジェクトのひとつですが,ブラウザごとに実装が異なりますので注意が必要です。リスト1の次の部分に注目してください。

  try {
    xmlReq = new ActiveXObject("Microsoft.XMLHTTP");
  } catch(e) {
    xmlReq = new XMLHttpRequest();
  }

 Microsoft.XMLHTTPオブジェクトは,Internet Explorerで利用可能なHTTP通信オブジェクトです。ここではまずブラウザがInternet Explorerであることを前提としてオブジェクトの生成を試み(tryブロック),失敗した場合には改めてXMLHttpRequestオブジェクトの生成を試みています(catchブロック)。XMLHttpRequestオブジェクトは,FirefoxやSafariなどのブラウザで利用可能なHTTP通信オブジェクトです。これによって,クライアントによるHTTP通信オブジェクトの実装の違いを吸収しているわけです。

 なお,以降では便宜上,Internet ExplorerのXMLHTTPオブジェクトも含めて,XMLHttpRequestオブジェクトと呼ぶことにします。XMLHttpRequestオブジェクトで利用可能なプロパティ/メソッドについては,表2にまとめています。これらプロパティ/メソッドの詳細については,登場の都度に紹介します。

表2●XMLHttpRequestオブジェクトの主なプロパティ/メソッド。[R|*]は読み取り専用のプロパティ,[R|W]は読み書き可能なプロパティ,[M]はメソッド。(*)が付いたメソッドは,sendメソッドによるHTTP通信が成功した場合にのみ利用可能
メンバー名 概要
[R|W] onreadystatechange HTTP通信の状態が変化したタイミングで呼び出されるコールバック関数
[R|*] readyState HTTP通信の状態を取得
[R|*] responseBody サーバーからの応答本体を取得
[R|*] responseText サーバーからの応答をプレーン・テキストとして取得
[R|*] responseXML サーバーからの応答をXMLDocumentオブジェクトとして取得
[R|*] status HTTP応答ステータスコードを取得(200=成功,500=内部サーバーエラー,など)
[R|*] statusText HTTPステータス・メッセージを取得
[M] abort() 現在のHTTP要求を中断
[M] getAllResponseHeaders() すべてのHTTP応答ヘッダーを取得(*)
[M] getResponseHeader(header) 指定されたHTTP応答ヘッダー(header)を取得(*)
[M] open(method ,url [,async [,user [,password]]]) 指定されたHTTPメソッドでHTTP要求を開始
[M] send(body) HTTP要求を送信
[M] setRequestHeader(header,value) HTTP要求に際して要求ヘッダーを追加

通信状態が変わったときに呼び出されるコールバック関数を定義する

 コールバック関数は,HTTP通信の状態が変化したタイミングで内部的に呼び出される関数です。コールバック関数を利用することで,以下のような処理を定義することが可能になります。

・応答待ちの状態を画面上に表示する
・サーバーから正常な応答を受け取ったタイミングでページの内容を更新する
・サーバーからエラーを受け取った場合にエラー・メッセージを表示する

 コールバック関数を定義するのは,onreadystatechangeプロパティの役割です。onreadystatechangeプロパティでは,

  xmlReq.onreadystatechange = showResponse;

のように,別に定義した関数名(ここではshowResponse)を指定することもできますが,本サンプルではよりシンプルに匿名関数を利用しています。匿名関数とは,その名の通り名前のない関数のことで,以下のようにプロパティ値に直接格納することもできます。

  xmlReq.onreadystatechange = function() {
...関数定義...
}

 リスト1のコールバック関数の処理のコードは次の通りです。処理の流れを図示すると図1のようになります。

var msg = document.getElementById("result");
if (xmlReq.readyState == 4) {  // サーバーから応答が返ってきたか
 if (xmlReq.status == 200) {  // サーバーの処理は成功したか
   msg.innerHTML = xmlReq.responseText;  // ページを更新
 } else {
   msg.innerHTML = "通信に失敗しました。";  // エラー・メッセージを表示
   }
} else {
  msg.innerHTML = "通信中…";  // 途中経過メッセージを表示
}

図1

 ここでは,readyStateプロパティの戻り値が4(全応答データを取得済み。表3参照)であり,かつ,statusプロパティの戻り値が200(サーバーでの処理が正常終了。表4参照)である場合に,サーバーから送信されてきたデータを取得し,これをid属性の値が"result"である要素に反映させているわけです(リスト1の下から4行目)。サーバーからの応答をプレーン・テキストとして取得するためには,responseTextプロパティを使用します。

表3●readyStateプロパティの戻り値
戻り値 概要

0

初期化されていない(openメソッドがまだ呼び出されていない)

1

ロード中(openメソッドは呼び出されたが,sendメソッドはまだ呼び出されていない)
2 ロード済み(sendメソッドは呼び出されたが,応答は取得していない。ステータス/ヘッダー情報はまだ利用できない)
3 一部の応答を取得(応答ステータス/ヘッダーは取得できるが,本体は取得できない)

4

全データを取得済み


表4●HTTP 1.1で利用可能な主なHTTPステータスコード
HTTPステータス 意味

200 OK

成功

401 Unauthorized

認証を要求
403 Forbidden アクセスを拒否
404 Not Found リソースが見つからない

500 Internal Server Error

内部サーバー・エラー
503 Service Unavailable サーバーが利用不可

 サーバーからの応答は取得したものの,サーバー側での処理が失敗している(statusプロパティが200以外)場合にはエラー・メッセージを,そもそもXMLHttpRequestオブジェクトがサーバーからの応答を取得していない(readyStateプロパティが4以外)場合には「通信中…」という経過報告メッセージを,それぞれ表示します。非同期通信であるAjaxの世界では,エンドユーザーに対して現在の状態を示すことは重要です。

 以上,今回はHTTP通信を行うための準備まで紹介しました。次回は引き続き,これらコールバック関数を利用して,実際のHTTP通信を行う部分について説明します。

特別コラム●文字コードはUTF-8に設定

 XMLHttpRequestオブジェクトで利用可能な文字コードは,原則として「UTF-8」のみです。Ajaxを利用するに際しては,サーバーサイド・アプリケーション側で必ず文字コードをUTF-8に設定してください。連載第2回のPHPプログラム(searchAjax.php)の場合は,以下の部分が該当します。


  mb_http_output('UTF-8');

  mb_internal_encoding('UTF-8');

ほかの文字コードを使用してマルチバイト文字を送信しようとすると,文字化けが発生する可能性がありますので,注意が必要です。なお,本サンプルでは「.php」ファイルに直接文字コードの設定を記述していますが,もちろん,環境が許すならば,これら文字コードの設定はphp.iniや.htaccess上で行うべきです。


山田祥寛(やまだ よしひろ)

Microsoft MVP for ASP/ASP .NET。執筆コミュニティ「WINGSプロジェクト」の代表でもある。主な近著に「XMLデータベース入門」「PEAR入門」「Smarty入門」「10日でおぼえる入門教室シリーズ(Jakarta・JSP/サーブレット・PHP・XML)」(以上,翔泳社),「今日からつかえるサンプル集シリーズ(JSP&サーブレット・PHP5・ASP・XML)」(以上,秀和システム),「書き込み式 SQLのドリル」(ソシム),「JSP/PHP/ASPサーバーサイドプログラミング徹底比較」(技術評論社)など。最近では,IT関連技術の取材,講演,監修まで広く手がける毎日。