サーバから非同期にレスポンスを受け取る方法 (Ajax)

Ajax (Asynchronous JavaScript + XML) で、サーバから非同期にレスポンスを受け取る方法について解説します。

ここで解説する方法では、jQueryなどのライブラリを必要としません。

XMLHttpRequestオブジェクト

プロパティ

分類 プロパティ※1 説明
  readyState short HTTPリクエストの状態
レスポンス ※2 responseText String レスポンス (ヘッダを含まない)
responseXML Document レスポンス (XMLとして解析済み)
responseType String 期待するレスポンスの型
response varies レスポンス (responseTypeの型で解析済み)
ステータス status short HTTPステータス コード
statusText String HTTPステータス コードの文字列表現
※1 すべて読み取り専用
※2 JSONで取得するには、eval()を使用します。responseTypeを'json'とします。
readyStateプロパティの値
名前 説明 発生状況
0 Uninitialized 初期状態 次のいずれか
  • open()メソッドの呼び出し前
  • abort()メソッドの呼び出し後
1 Open リクエスト未送信 open()メソッドの呼び出し後
2 Sent レスポンス未受信 send()メソッドの呼び出し後
3 Receiving レスポンス受信中 サーバからデータを受信中※1
4 Loaded レスポンス受信済み サーバのレスポンスの受信が完了
※1 おおきなサイズのデータを受信するとき、Firefoxでは複数回イベントが発生しますが、IEでは一度だけです。

メソッド

メソッド 説明
open HTTPリクエスト パラメータを初期化する
send HTTPリクエストを送信する
abort リクエストを停止する
getAllResponseHeaders すべてのHTTPレスポンス ヘッダを未解析の文字列として取得する
getResponseHeader 指定のHTTPレスポンス ヘッダの値を取得する
setRequestHeader 未送信のリクエストに、HTTPリクエスト ヘッダを設定する
Methods - XMLHttpRequest - Web APIs | MDN

イベントハンドラ

イベントハンドラ 説明
onreadystatechange readyStateプロパティが変更されるごとに呼び出される
Events - XMLHttpRequest - Web APIs | MDN

XMLHttpRequestオブジェクトの生成

XMLHttpRequestオブジェクトの生成は、Internet Explorer 7より前とそれ以外のブラウザで異なります。よって複数の方法で試行する必要があります。

IE7より前のサポートを考慮しないならば、new XMLHttpRequest()だけで十分です。

// XMLHttpRequestオブジェクトを生成する
var xmlHttpRequest;

try
{
    xmlHttpRequest = new XMLHttpRequest();
}
catch( e )
{
    try
    {
        // IE6向けの処理
        xmlHttpRequest = new ActiveXObject( 'Msxml2.XMLHTTP' );
    }
    catch( e )
    {
        // IE5とIE5.5向けの処理
        xmlHttpRequest = new ActiveXObject( 'Microsoft.XMLHTTP' );
    }
}

非同期イベントを処理する関数の登録

// 非同期の通知を受け取るイベントハンドラを登録する
xmlHttpRequest.onreadystatechange = function()
{
    var READYSTATE_COMPLETED = 4; // readyStateの値
    if( this.readyState == READYSTATE_COMPLETED )
    {
        var HTTP_STATUS_OK = 200; // HTTPステータス コード
        if( this.status == HTTP_STATUS_OK )
        {
            // サーバから受信したレスポンスを表示する
            alert( this.responseText );
        }
        else
        {
            // エラーを表示する
            alert( this.status + this.statusText );
        }
    }
}

※ リクエストの成否に無関心で、レスポンスを受け取る必要もなければ、このようにreadystatechangeイベントに反応する必要はありません。

受信に失敗するときには、XmlHttpRequest.statusを確認します。

readyStateが4を返すのを確認せず、レスポンスの受信完了の前にレスポンスを読み込もうとすると、InvalidStateError例外が発生します。

HTTPリクエストの初期化と送信

リクエストの詳細を設定し、そしてリクエストを送信します。

// HTTPリクエストパラメータを初期化する
xmlHttpRequest.open( 'GET', requestUrl );

// HTTPリクエストを送信する
xmlHttpRequest.send( null );

HTTPリクエストの初期化

void open(
    String method,   // HTTPメソッド (GET, POST, HEAD, etc...)
    String url,      // リクエスト対象のURL
    boolean async,   // 非同期に処理するかどうか (省略もしくはtrueで非同期)
    String username, // 認証情報 (ユーザー名)
    String password  // 認証情報 (パスワード)
    )
open() - XMLHttpRequest - Web API Interfaces | MDN

メソッド名はopenとなっていますが、このメソッドは接続を開いたりはしません。send()メソッドを実行するためのリクエストを初期化するだけです。既定では非同期ですが、第3引数のasyncをfalseとすることで同期通信とすることも可能です。

リクエスト対象とできるURLには、以下の制限があります。

しかしJSONPでデータを受け取れるならば、スクリプトを動的に読み込む方法同一起源ポリシーの制約を回避できます。

同一生成元ポリシー | MDN

HTTPリクエストの送信

void send(
    Object body // リクエストの本体
    )
send() - XMLHttpRequest - Web API Interfaces | MDN

POSTでリクエストする場合には、body引数でリクエスト本体を指定します。それ以外のメソッドではnullを指定します。

レスポンスの処理

同一のレスポンスが予期せずくり返されるならば、それはキャッシュの影響かも知れません。そのような場合にはキャッシュが無効化されるようにリクエストします。

レスポンスのデータ型

データの種類によっては、それを解析した結果として受け取ることができます。

テキスト

レスポンスがテキストならば、responseTextプロパティからString型で取得できます。

XML

レスポンスがXMLならば、responseXMLからDocument型で取得できます。ただしXMLとして解析されるためには、次の条件を満足する必要があります。

  1. Content-Typeヘッダに「text/xml」や「application/xml」などが指定され、XMLドキュメントであることが明示されている。
  2. エラーなく解析できる、XMLマークアップで構成されている。

この条件を満たさない場合、このresponseXMLはnullを返します。

その他

XML以外のデータについては、responseTypeでその型を指定することで、期待する型として解析された結果をresponseから取得できます。

responseTypeの値
responseプロパティのデータ型
'' String
'arraybuffer' ArrayBuffer
'blob' Blob
'document' Document
'json' Object
'text' String
responseType - XMLHttpRequest - Web API Interfaces | MDN

ただしresponseTypeで指定可能な値はブラウザによってサポートが異なり、サポートされないブラウザでは指定の型で取得できません。Browser compatibility - XMLHttpRequest - Web API Interfaces | MDN

その場合でもJSONについては、responseTextプロパティをeval()に渡すことで、JavaScriptのオブジェクトとして取得することが可能です。なおレスポンスが指定したresponseTypeに合致しない場合には、responseはnull、responseTextはundefinedを返します。

サンプルコード

レスポンスとしてJSONを期待する場合を考えます。

var xmlHttpRequest = new XMLHttpRequest();
xmlHttpRequest.onreadystatechange = function()
{
    if( this.readyState == 4 && this.status == 200 )
    {
        if( this.response )
        {
            // JSONとして取得できたならばresponseはObject型であるため、
            // そのプロパティのようにレスポンスのデータにアクセスできます。
            alert( this.response.foo );
        }
    }
}

xmlHttpRequest.open( 'GET', 'test.json', true );
xmlHttpRequest.responseType = 'json';
xmlHttpRequest.send( null );