これでできる! クロスブラウザJavaScript入門

第12回 XMLHttpRequest入門

この記事を読むのに必要な時間:およそ 4 分

こんにちは,太田です。前回はJSONPについて解説しました。今回は,XMLHttpRequestについて解説していきます。

XMLHttpRequestとは

XMLHttpRequestはブラウザ上でサーバーとHTTP通信を行うためのAPIです。

名前にXMLが付いていますがXMLに限ったものではなく,HTTPリクエストを投げてテキスト形式かDOMノードでレスポンスを受け取る機能を持っています。

仕様としてはW3CよりXMLHttpRequestとして定義されており,2010年8月3日にCandidate Recommendation(勧告候補)となったばかりです。また,XMLHttpRequest Level 2の策定も進められています。

XMLHttpRequestの機能と特徴

前回のJSONPと比べると機能的には大きな違いはありません。ただ,スキーム,ドメイン,ポート(これをまとめてオリジンと呼びます)すべてが一致するしたURLとしか通信できない点がJSONPとの決定的な違いです。この制限により,(比較的)安全にサーバーと通信することができます。

XMLHttpRequestの簡単な歴史

XMLHttpRequestは元々はIE 5において,ActiveXObjectのMicrosoft.XMLHTTPコンポーネントとして実装されたのが始まりです。詳しくはAlex Hopmann's Web SiteのThe story of XMLHTTP日本語訳で語られているように,名前にXMLが入ったのは単に製品の出荷に間に合わせるための都合だったと書かれています。

Mozillaがすぐさま追従してXMLHttpRequestを実装し,Opera,SafariもMozillaの実装に従いました。さらにIE 7もMozillaの実装にあわせて改めてXMLHttpRequestを実装したため,XMLHttpRequestは実質的な標準APIとなりました。またその動きに合わせてW3Cでの標準化も進められ,2010年8月3日に勧告候補にまで至りました。

XMLHttpRequestの使い方

まずはXMLHttpRequestの簡単なサンプルを見てみましょう。次のコードは現在みているページをXMLHttpRequestで取得して,テキストエリアにソースを表示するサンプルです。

XMLHttpRequestのサンプル(IE 6以外)

var btn1 = document.getElementById('xhr-btn1');
btn1.onclick = function(){

  var xhr = new XMLHttpRequest();
  xhr.open('GET', location.href, true);
  xhr.onreadystatechange = function(){
    // 本番用
    if (xhr.readyState === 4 && xhr.status === 200){
      var result1 = document.getElementById('xhr-result1');
      result1.value = xhr.responseText;
    }
    // ローカルファイル用
    if (xhr.readyState === 4 && xhr.status === 0){
      var result1 = document.getElementById('xhr-result1');
      result1.value = xhr.responseText;
    }
  };
  xhr.send(null);
};

このようにXMLHttpRequestの基本的な使い方は,次の4ステップからなります。

  • new XMLHttpRequestでオブジェクトを作る
  • openメソッドで送信時のメソッド,送信先URL,非同期通信か同期通信か真偽値で設定
  • onreadystatechangeで読み込み時の動作を指定
  • sendメソッドでリクエストを送信,引数はGETの場合nullを,POSTの場合はデータを&で繋げた文字列にして渡す。

openメソッドの第3引数で同期通信にすることも可能ですが,同期通信はsendしてからサーバーのレスポンスがあるまでJavaScriptの処理をすべて止めてしまうため,ユーザーを待たせてしまいます。省略時は非同期通信になるので,省略してもかまいません。

なお,呼び出す順番はこの順番を崩さないようにしましょう。まずopenしてからプロパティなどを編集し,最後にsendを実行する形が最も確実に動作します。

レスポンスの処理

onreadystatechangeで「読み込み途中」,および「読み込み完了」・「失敗」時の処理を行います。

まず,読み込みの状態を管理するのはreadyStateプロパティです。readyStateが4の時,読み込みの完了を示します。

そして,statusプロパティによってその読み込みが成功したのか,失敗したのかといったことがわかります。成功時のステータスコードは通常200なので,サーバー側で特殊な処理をしていない限りは200かどうかをチェックするだけで十分です。

読み込みが完了していてステータスが200なら,responseTextからレスポンスの内容を読み取ることができるでしょう。

レスポンスとしてはresponseXMLというプロパティもありますが,こちらは名前の通りXMLを受け取ったときにしかその値を読み取ることができません。具体的にはレスポンスヘッダのContent-Typeにxmlが含まれていて,XMLとしてパース可能である必要があります。

JSONを受け取った場合

XMLHttpRequestのレスポンスとしてJSONを受け取った場合,それはresponseTextのデータとして読み取ることになります。つまり,それはJavaScriptのオブジェクトではありません。できれば直接JSONをオブジェクトとして読み取りたいところですが,今のところそういったAPIは用意されていません。従ってJSONをパースしてオブジェクトに変換する必要があります。

JSONのパースに対応しているのは各ブラウザの比較的新しいバージョンに限られます。そのため,手軽にJSONをJavaScriptに変換できるevalなどがよく使われてしまっています。しかし,それらは本来のJSON形式でなくとも解釈できてしまうため,安全とはいえません(もちろんJSONPにくらべれば格段に安全ではありますが)。そこでjson.orgで公開されているjson2.jsを用いるのが良い選択です。なお,json2.jsの1行目にはalertが入っています。これはjson2.jsを直接参照されないようにするための予防策です。

json2.jsは読み込むだけでJSON.parseメソッドが利用可能になります。

JSON.parseのサンプル

  var data = JSON.parse(xhr.responseText);

IE 6対応

IE 7からXMLHttpRequestに対応したと書きましたが,つまりIE 6にはXMLHttpRequestがありません。その代わりに最初に出てきたActiveXのXMLHTTPを用います。なおXMLHTTPにはいくつかのバージョンがあり,なるべく新しいバージョンを使えるように次のようにXMLHttpRequestを定義するとよいでしょう。

XMLHttpRequestのサンプル(IE 6含む)

if (!window.XMLHttpRequest){
  XMLHttpRequest = function () {
    try {
      return new ActiveXObject("Msxml2.XMLHTTP.6.0");
    } catch (e) {}
    try {
      return new ActiveXObject("Msxml2.XMLHTTP.3.0");
    } catch (e) {}
    try {
      return new ActiveXObject("Msxml2.XMLHTTP");
    } catch (e) {}
    throw new Error("This browser does not support XMLHttpRequest.");
  };
}
var btn2 = document.getElementById('xhr-btn2');
btn2.onclick = function(){
  var xhr = new XMLHttpRequest();
  xhr.open('GET', location.href, true);
  xhr.onreadystatechange = function(){
    if (xhr.readyState === 4 && xhr.status === 200){
      var result2 = document.getElementById('xhr-result2');
      result2.value = xhr.responseText;
    }
    if (xhr.readyState === 4 && xhr.status === 0){
      var result2 = document.getElementById('xhr-result2');
      result2.value = xhr.responseText;
    }
  };
  xhr.send(null);
};

XMLHttpRequestオブジェクトの作り方以外はIE 6もほぼ同様に扱うことができます。

著者プロフィール

太田昌吾(おおたしょうご,ハンドルネーム:os0x)

1983年生まれ。JavaScriptをメインに,HTML/CSSにFlashなどのクライアントサイドを得意とするウェブエンジニア。2009年12月より、Google Chrome ExtensionsのAPI Expertとして活動を開始。

URLhttp://d.hatena.ne.jp/os0x/

コメント

  • XMLHttpRequest入門

    XMLHttpRequestのサンプルを実行してみましたが、下記の問題が発生しました。お忙しいところ、申し訳ありませんが、ヒントか参考になるページがあれば、教えていただけないでしょうか。

    ①Internet Explorer 8では「アクセスが拒否されました」というエラーが発生します。

    ②Google Chromeではlocation.hrefのファイルは読み込みますが、同じフォルダにある他のファイルは読み込めません。

    よろしくお願いします
    Martin B.

    Commented : #1  m-bagatella (2012/12/19, 14:03)

コメントの記入