XMLHttpRequest()
ActiveXObject(ProgID : String [, location : String])
JavaScriptの非同期通信に利用される XMLHttpRequest()
の解説まとめ。Ajax と呼ばれることもあります。
XMLHttpRequest()
// --- XMLHttpRequest
if (!'XMLHttpRequest' in this) {
this.XMLHttpRequest = (function () {
var i, l;
for (i = 0, l = arguments.length; i < l; i++) {
try {
return arguments[i];
}
catch (err) {}
}
return null;
})(
function () { return new ActiveXObject('Msxml2.XMLHTTP.6.0'); },
function () { return new ActiveXObject('Msxml2.XMLHTTP.3.0'); });
}
XMLHttpRequest()
はモダンブラウザ(Firefox, Google Chrome, Opera等) と IE7+ から対応したメソッドですが、上記コードを取り込むことで IE6- でも標準の XMLHttpRequest()
と同じように互換オブジェクトを生成できるようになります。
var req = new XMLHttpRequest(); // IE6- でもこの記述でXMLHttpRequest互換のオブジェクトを生成できる
ここでは例外処理として、null
を返していますが、new XMLHttpRequest()
の戻り値が null
になるわけではない事に注意してください。
new演算子を使用した時点で必ずオブジェクトを生成するので、下記コードは期待通りに動作しません。
var req = new XMLHttpRequest();
if (req) { // req値 が null か否か
req.open ('GET', 'test.txt', true);
} else {
throw new Error ('[object XMLHttpRequest] を生成できませんでした');
}
例外処理を行うには [object XMLHttpRequest]
に存在するプロパティをみて、判断する必要があります。
var req = new XMLHttpRequest();
if ('open' in req) { // req.open の存在チェック
req.open ('GET', 'test.txt', true);
} else {
throw new Error ('[object XMLHttpRequest] を生成できませんでした');
}
ActiveXObject(ProgID : String [, location : String])
XMLHttpRequest互換のオブジェクトを生成する時、new ActiveXObject()
の 第一引数(ProgID) に指定される値は何種類かあります。その内のいくつかは指定すべきではないとMicrosoft中の人が指摘しています。
// --- 使うべきオブジェクト
new ActiveXObject( 'Msxml2.XMLHTTP.3.0' ); // バージョン3.0 広範に利用されているので、今後も bugfix を行う
new ActiveXObject( 'Msxml2.XMLHTTP.6.0' ); // バージョン6.0 は最新版なので bugfix を続ける
// --- 使うべきではないオブジェクト
new ActiveXObject( 'Microsoft.XMLHTTP' ); // Microsoft接頭辞は古いので指定すべきではない
new ActiveXObject( 'Msxml.XMLHTTP' ); // Msxml2接頭辞を指定すべき
new ActiveXObject( 'Msxml2.XMLHTTP' ); // バージョンを省略すると 3.0 として扱われるので、バージョンは明記すべき
new ActiveXObject( 'Msxml2.XMLHTTP.4.0' ); // バージョン4.0 は bugfix が行われないので、3.0 か 6.0 を指定すべき
new ActiveXObject( 'Msxml2.XMLHTTP.5.0' ); // バージョン5.0 は bugfix が行われないので、3.0 か 6.0 を指定すべき
W3Cで公開されている仕様書によれば、setRequestHeader()
でキャッシュ制御のためのヘッダを送信すれば、キャッシュを読み込まないように出来る、とあります。
If the user agent implements a HTTP cache it should respect Cache-Control request headers set by
setRequestHeader()
(e.g.,Cache-Control: no-cache
bypasses the cache). It must not sendCache-Control
orPragma
request headers automatically unless the end user explicitly requests such behavior (e.g. by (force-)reloading the page).For 304 Not Modified responses that are a result of a user agent generated conditional request the user agent must act as if the server gave a 200 OK response with the appropriate content. The user agent must allow setRequestHeader() to override automatic cache validation by setting request headers (e.g.,
If-None-Match
,If-Modified-Since
), in which case 304 Not Modified responses must be passed through. [RFC2616]
モダンブラウザは no-cache
でキャッシュ読み込みを回避できますが、IEは回避できないので If-Modified-Since
も一緒に指定します。
var req = new XMLHttpRequest();
req.open ('GET', 'test.txt', true);
req.setRequestHeader('Pragma', 'no-cache'); // HTTP/1.0 における汎用のヘッダフィールド
req.setRequestHeader('Cache-Control', 'no-cache'); // HTTP/1.1 におけるキャッシュ制御のヘッダフィールド
req.setRequestHeader('If-Modified-Since', 'Thu, 01 Jun 1970 00:00:00 GMT'); // 指定日時以降に更新があれば内容を返し、更新がなければ304ステータスを返すヘッダフィールド。古い日時を指定すれば、必ず内容を返す。
XMLHttpRequest()
はセキュリティ上の理由から、異なるドメインにリクエストを発行できません。
XMLHttpRequest Level 2ではサーバ側で適切なヘッダを返せば、クロスドメイン制限を回避できます。
XMLHttpRequest Level 2 で異なるドメインにリクエストを発行するには、リクエスト先のサーバに Access-Control-Allow-Origin
ヘッダフィールドを設定します。
下例では、http://example.jp
からのリクエストを許可しています。
Access-Control-Allow-Origin: http://example.jp
リクエストの仕方は XMLHttpRequest()
と同じですが、IE8だけは XDomainRequest
のオブジェクトが別に定義されています。
var req = this.XDomainRequest ? new XDomainRequest() : new XMLHttpRequest();
下記ボタンをクリックすると、XMLHttpRequest.txt の内容が alert()
されます。
XMLHttpRequest.js にもサンプルコードがありますが、HTMLを用意していないので適当に読んでください。
ここをクリックしてください
<script type="text/javascript"><!--
// --- XMLHttpRequest
if (!'XMLHttpRequest' in this) {
this.XMLHttpRequest = (function () {
var i, l;
for (i = 0, l = arguments.length; i < l; i++) {
try {
return arguments[i];
}
catch (err) {}
}
return null;
})(
function () { return new ActiveXObject('Msxml2.XMLHTTP.6.0'); },
function () { return new ActiveXObject('Msxml2.XMLHTTP.3.0'); });
}
// --- 非同期通信を実行する関数
function getRequest () {
var req = new XMLHttpRequest(),
method, url, async, data;
if (!'open' in req) { // req.open の存在チェック
req = null;
return false;
}
method = 'GET'; // リクエストメソッド
url = './XMLHttpRequest.txt'; // リクエストURL
async = true; // 非同期通信フラグ (true = 非同期通信 / false = 同期通信)
data = null; // リクエスト先に送信するデータ (GETリクエストは送信するデータがないので null にする)
req.open (method, url, async); // メソッド, URL, 同期フラグ を指定する
req.onreadystatechange = onReadystatechange; // onreadystateイベントハンドラ属性に関数をセット
// キャッシュを無効にする
req.setRequestHeader('Pragma', 'no-cache');
req.setRequestHeader('Cache-Control', 'no-cache');
req.setRequestHeader('If-Modified-Since', 'Thu, 01 Jun 1970 00:00:00 GMT');
req.send (data); // データを送信する (null)
// readystate(XMLHttpRequestオブジェクトを準備する状態) が変化した時に呼ばれる関数)
function onReadystatechange () {
// readyStateをチェック
// http://www.w3.org/TR/XMLHttpRequest/#states
if (req.readyState === 4) { // readyState === 4 はデータ読み込みが完了した状態
// HTTPステータスコードをチェック
if (req.status === 200 && req.responseText) { // HTTPステータスコード200 は「リクエスト成功」を表す
alert(req.responseText); // サーバから得た内容 (文字列リテラル) を alert() する
}
req.abort(); // 通信を中断する
req.onreadystatechange = new Function; // onreadystatechangeイベントハンドラ属性に空のFunctionオブジェクトを代入 (イベントハンドラ属性を初期化することで、IE6のメモリリークを回避する。prototype.js の回避方法と似ているかも。)
req = method = url = async = data = null; // ActiveX() が生成するXMLHttpRequest互換オブジェクトをクロージャが参照を保持すると IE6 で循環参照(メモリリーク) するので、null で埋めて回避しておく
}
}
function finalize () {
req = method = url = data = async = null;
}
}
// --- イベントリスナー関数
function clickListener (event) {
var button = event.target || event.srcElement;
if (button.id !== 'Test') { return; }
getRequest ();
}
// --- イベントの定義
if (document.addEventListener) { // for Gecko/Opera/Webkit/IE9+
document.addEventListener('click', clickListener, false);
} else if (document.attachEvent) { // for IE8-
document.attachEvent('onclick', clickListener);
}
//--></script>
</head>
<body>
<p><span id="Test" class="button">ここをクリックしてください</span></p>