このページはコミュニティーの尽力で英語から翻訳されました。MDN Web Docsコミュニティーについてもっと知り、仲間になるにはこちらから。
XMLHttpRequest の使い方
Baseline Widely available *
This feature is well established and works across many devices and browser versions. It’s been available across browsers since 2015年7月.
* Some parts of this feature may have varying levels of support.
このガイドでは、ウェブサイトとサーバーの間でデータ交換をするために、XMLHttpRequest を使用してHTTP リクエストを発行する方法を紹介します。
XMLHttpRequest のよくある使用例やもっと分かりにくい使用例も含まれています。
HTTP リクエストを送るには、
XMLHttpRequestオブジェクトを作成し、- URL を開き、
- リクエストを送信します。
トランザクションが完了すると、XMLHttpRequest オブジェクトには結果のHTTP ステータスコードやレスポンスの本文などの有益な情報が格納されます。
function reqListener() { console.log(this.responseText);}const req = new XMLHttpRequest();req.addEventListener("load", reqListener);req.open("GET", "http://www.example.org/example.txt");req.send();In this article
リクエストの種類
XMLHttpRequest によって作成されたリクエストは、非同期または同期のいずれかの方法でデータを取得することが可能です。リクエストをどちらの方法で行うかは、XMLHttpRequest.open() メソッドのオプションのasync 引数(第 3 引数)で指示することができます。この引数をtrue にするか、指定しなければXMLHttpRequest は非同期で処理され、それ以外だと同期的に扱われます。これら二つの種類のリクエストに関する詳細および使用例は、同期および非同期リクエストのページを参照してください。ウェブワーカー以外では同期リクエストを使用しないでください。
メモ:コンストラクター関数XMLHttpRequest は XML 文書に限定されていません。"XML" で始まっているのは、これが作成されたときに非同期データ交換に使用されていた主要な形式が XML であったからです。
レスポンスの取り扱い
XMLHttpRequest() コンストラクターに定義されているresponse 属性は何種類かがあります。これらはクライアントにXMLHttpRequest にレスポンスのステータスに関する重要な情報を作るように指示します。テキスト以外のレスポンス型を扱う場合は、後の節で概説する操作や解析が入ることがあるかもしれません。
responseXML プロパティの解析と操作
リモートの XML 文書のコンテンツを得るためにXMLHttpRequest を使う場合、responseXML プロパティが解釈済みの XML 文書を含む DOM オブジェクトとなります。これによって、操作や解析が難しくなる可能性があります。この XML 文書を解析するには主な 4 つの方法があります。
- 一部を指すためにXPath を使う。
- 手動でXML を構文解析およびシリアライズして文字列やオブジェクトにする。
XMLSerializerを使ってDOM ツリーを文字列やファイルにシリアライズする。- 事前に XML 文書の中身が常に分かっている場合は
RegExpを使うこともできます。改行をRegExpでスキャンする場合に、改行を除去した方がよく見えることもありますが、 XML コードが少しでも変更されると、メソッドは失敗しがちなため、このメソッドは「最後の手段」です。
メモ:XMLHttpRequest はresponseXML プロパティを使用することによって、 HTML を解釈できるようになりました。この方法について学ぶには、XMLHttpRequest における HTML の扱いについての記事をお読みください。
HTML 文書を含む responseText プロパティの処理
XMLHttpRequest を使ってリモート HTML ウェブページのコンテンツを取得する場合、responseText プロパティは生の HTML が入った文字列です。これは操作や解析が難しいことを示しています。この生の HTML 文字列を分析し解析するには、主に 3 つの方法があります。
- XMLHttpRequest における HTML の扱いの記事で紹介されている
XMLHttpRequest.responseXMLプロパティを使用する。 - 文書フラグメントの本体を
fragment.body.innerHTMLを通してコンテンツに挿入し、そのフラグメントの DOM を走査する。 - 事前に HTML の
responseTextの中身が常に分かっている場合はRegExpを使うこともできます。改行を RegExp でスキャンする場合に、改行を除去した方がよく見えることもありますが、 HTML 文書が少しでも変更されると、メソッドは失敗しがちなため、このメソッドは「最後の手段」です。
バイナリーデータの扱い
XMLHttpRequest はテキストデータの送受信に最もよく使われますが、バイナリーコンテンツの送受信にも使えます。XMLHttpRequest のレスポンスをバイナリーデータ送信に強制するためのテストされたメソッドがいくつかあります。この中にはXMLHttpRequest オブジェクトのoverrideMimeType() メソッドを活用して使える解決法としているものも入っています。
const req = new XMLHttpRequest();req.open("GET", url);// バイナリー文字列として未処理のデータを取得するreq.overrideMimeType("text/plain; charset=x-user-defined");/* … */しかし、もっと新しいテクニックも使用できます。responseType 属性がいくつもの追加のコンテンツ型に対応するようになったので、バイナリーデータの送信や受信がずっと簡単になりました。
例えばこのスニペットでは、responseType に"arraybuffer" を使用して、生のバイナリーデータを格納できるArrayBuffer オブジェクトにリモートコンテンツを取得しています。
const req = new XMLHttpRequest();req.onload = (e) => { const arraybuffer = req.response; // responseText ではない /* … */};req.open("GET", url);req.responseType = "arraybuffer";req.send();その他の例は、バイナリーデータの送受信 ページを確認してください。
進捗の監視
XMLHttpRequest は、リクエストが処理されている間に発生する様々なイベントを待受けする機能を提供しています。これには定期的な進捗の通知、エラーの通知、などが含まれます。
XMLHttpRequest の転送を監視する DOMprogress イベントの対応は、progress events 仕様(英語)に従います。このイベントはProgressEvent インターフェイスを実装しています。進行中の転送の状態を特定するために監視することができる実際のイベントは、以下の通りです。
const req = new XMLHttpRequest();req.addEventListener("progress", updateProgress);req.addEventListener("load", transferComplete);req.addEventListener("error", transferFailed);req.addEventListener("abort", transferCanceled);req.open();// …// サーバーからクライアントへの転送の進捗 (ダウンロード)function updateProgress(event) { if (event.lengthComputable) { const percentComplete = (event.loaded / event.total) * 100; // … } else { // 全体の長さが不明なため、進捗情報を計算できない }}function transferComplete(evt) { console.log("転送が完了しました。");}function transferFailed(evt) { console.log("ファイルの転送中にエラーが発生しました。");}function transferCanceled(evt) { console.log("ユーザーが転送をキャンセルしました。");}XMLHttpRequest を使ってデータ転送を行うときに送られる色々なイベントへのためのイベントリスナーを追加しています。
メモ:イベントリスナーはリクエストのopen() を呼び出す前に追加する必要があります。そうしないとprogress イベントは発生しません。
この例ではupdateProgress() 関数で指定される進捗イベントハンドラーは、イベントのtotal およびloaded フィールドで、転送すべき総バイト数とこれまでに転送したバイト数を受け取ります。ただし、lengthComputable フィールドが false の場合、合計の長さは分からないので 0 になります。
進捗イベントはダウンロード、アップロードの両方に存在します。ダウンロードのイベントは、上記サンプルのように、XMLHttpRequest オブジェクトそのもので発生します。アップロードのイベントは下記のように、XMLHttpRequest.upload オブジェクトで発生します。
const req = new XMLHttpRequest();req.upload.addEventListener("progress", updateProgress);req.upload.addEventListener("load", transferComplete);req.upload.addEventListener("error", transferFailed);req.upload.addEventListener("abort", transferCanceled);req.open();メモ:進捗イベントはfile: プロトコルでは利用できません。
progress イベントは、受信したデータの塊ごとに発生します。 progress イベントが発行される前に最後のパケットを受信して接続が閉じられた場合には、最後の塊でも発生します。この場合、 progress イベントは、そのパケットに対して load イベントが発生したときに自動的に発行されます。これで、 "progress" イベントを見るだけで、確実に進捗を監視できるようになりました。
ロードを終える 3 つの条件(abort,load,errorのいずれか)をloadend イベントで検出することもできます。
req.addEventListener("loadend", loadEnd);function loadEnd(e) { console.log( "The transfer finished (although we don't know if it succeeded or not).", );}注意点として、loadend イベントで受け取った情報から、どの条件で動作が終了したのかを確かめる方法はありません。しかし、これを使ってすべての転送終了シナリオにて行う必要のあるタスクを処理できます。
最終更新日の取得
function getHeaderTime() { console.log(this.getResponseHeader("Last-Modified")); // 有効な GMTString の日付または null}const req = new XMLHttpRequest();req.open( "HEAD", // ヘッダーのみが必要であれば HEAD を使用する "your-page.html",);req.onload = getHeaderTime;req.send();最終更新日付が変わった時に何かする
2つの関数を作ってみましょう。
function getHeaderTime() { const lastVisit = parseFloat( window.localStorage.getItem(`lm_${this.filepath}`), ); const lastModified = Date.parse(this.getResponseHeader("Last-Modified")); if (isNaN(lastVisit) || lastModified > lastVisit) { window.localStorage.setItem(`lm_${this.filepath}`, Date.now()); isFinite(lastVisit) && this.callback(lastModified, lastVisit); }}function ifHasChanged(URL, callback) { const req = new XMLHttpRequest(); req.open("HEAD" /* use HEAD - we only need the headers! */, URL); req.callback = callback; req.filepath = URL; req.onload = getHeaderTime; req.send();}そしてテストします。
// ファイル "yourpage.html" をテストするifHasChanged("your-page.html", function (modified, visit) { console.log( `The page '${this.filepath}' has been changed on ${new Date( modified, ).toLocaleString()}!`, );});現在のページが変更されたかどうかを知りたい場合は、document.lastModified についての記事をお読みください。
サイトをまたがる XMLHttpRequest
現在のブラウザーは、オリジン間リソース共有 (Cross-Origin Resource Sharing, CORS) を実装することでサイト間リクエストに対応しています。サーバーがウェブアプリケーションのオリジンからのリクエストを許可するように構成されている場合のみ、XMLHttpRequest は動作します。それ以外の場合は、INVALID_ACCESS_ERR 例外が投げられます。
キャッシュをバイパスする
ブラウザー間で互換性のある、キャッシュをバイパスするアプローチは、 URL にタイムスタンプを追加することで、適切に "?" 又は "&" を付け加えます。例えば以下のようにします。
http://example.com/bar.html -> http://example.com/bar.html?12345http://example.com/bar.html?foobar=baz -> http://example.com/bar.html?foobar=baz&12345
ローカルのキャッシュは URL によって索引づけられるため、これですべてのリクエストが固有のものとなり、それによってキャッシュをバイパスします。
以下のコードを使用すると、自動的に URL を調整することができます。
const req = new XMLHttpRequest();req.open("GET", url + (/\?/.test(url) ? "&" : "?") + new Date().getTime());req.send(null);セキュリティ
サイト間スクリプトを有効にするための推奨される方法は、 XMLHttpRequest へのレスポンスの中で HTTP のAccess-Control-Allow-Origin ヘッダーを使用することです。
XMLHttpRequests の停止
XMLHttpRequest がstatus=0 およびstatusText=null を受信して終了すると、リクエストを実行することが許可されていないことを意味します。これは未送信 (UNSENT) 状態です。この原因の多くは、 XMLHttpRequest がopen() の時にXMLHttpRequest のオリジン(XMLHttpRequest が作成された場所)が変更されたことによるものです。これは例えば、 XMLHttpRequest を持ったページで onunload イベントが発生し、ウィンドウが閉じようとしている時に XMLHttpRequest が作成され、ウィンドウがフォーカスを失って他のウィンドウがフォーカスを得たときにリクエストの送信(言い換えればopen())が行なわれた場合に発生することがあります。この問題を防ぐ最も効果的な方法は、新しいウィンドウのDOMActivate イベントのリスナーを、unload イベントが発生したときに設定することです。
仕様書
| Specification |
|---|
| XMLHttpRequest> # interface-xmlhttprequest> |