huguma’s blog (仮)

IT技術関連中心の備忘録

XMLHTTPRequestによるバイナリデータ取得(モダンブラウザ専用)

現在Web Audio APIを利用したアプリケーションを書いていますが、オーディオサンプルをロードするためにXMLHTTPRequest(以下XHR)を使って波形データをロードする処理が必要になったのでreminderをここに残しておきます。

XHRでテキストデータを受信する場合はjQueryjQuery.ajaxを使うのが簡単で互換性も確保できます。しかしバイナリデータの場合はXHRを直接使う必要があります。

jQueryは今のところバイナリデータを扱うような作りにはなっていません(jquery ajax バイナリデータなどと検索してみて下さい)。

バイナリファイルの受信方法は次のMozillaドキュメントに解説があります。

https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest#Handling_binary_data

Mozillaドキュメントの多くは和訳もあり、上記URLのen-USjaに変えれば和訳ドキュメントを見ることができます。しかし今この文章を書いている時点ではまだ作業中で半分も日本語になってない状態です。

設定方法は2種類あります。

  • .overrideMimeType("text/plain; charset=x-user-defined") (旧式)
  • .responseType = 'arraybuffer' (新式)

今回はWeb Audio APIを使うことが前提なので新方式を使います。パターンは次のようになります(Mozillaドキュメントより抜粋)。

var oReq = new XMLHttpRequest();
oReq.onload = function(e) {
  var arraybuffer = oReq.response; // not responseText
  /* ... */
}
oReq.open("GET", url, true);
oReq.responseType = "arraybuffer";
oReq.send();

全体の流れを確認します。

  • まずXHRオブジェクトを生成
  • 送信前に設定(順不同)
    • .onloadに応答時のハンドラを設定(詳しくは後で...)
    • .open(メソッド, URL, true) で相手先を設定
      • ちなみに最後がfalseだと結果が返るまでブロック(やってはいけない!)
    • .responseTypeを'arraybuffer'に設定(今回はこれが一番のポイント)
  • .send()で送信

responseType属性(送信用)とresponse属性(応答用)のリファレンスは次の通り。

今回必要な部分だけ簡単にまとめます。

  • 送信前に.responseTypeを'arraybuffer'にする
    • 応答時は.responseにArrayBufferオブジェクトを返す
    • 失敗時(404など)でも空のArrayBufferを返すことに注意

http://www.w3.org/TR/XMLHttpRequest/#arraybuffer-response-entity-body

応答処理用ハンドラはonloadに設定します。

  • .onload = function (event) { ... }

loadイベントの他にloadstart(開始時)、progress(処理中)、error(エラー発生)などがあります。全イベントの一覧は次の通りです。

http://www.w3.org/TR/XMLHttpRequest/#event-handlers

errorはサーバ応答がない場合などの処理用で、例えば404(not found)などは(サーバが応答しているので)loadで処理することに注意して下さい。

引数のeventはProgressEventで、progressイベント処理中に進行状況を取得するのに用います(それ以外にはあまり使い道なし)。

https://dvcs.w3.org/hg/progress/raw-file/tip/Overview.html#progressevent

  • .lengthComputable HTTPレスポンスヘッダにContent-Lengthがあればtrue
  • .loaded 実際に転送したサイズ
  • .total Content-Lengthがあればそのサイズ、なければ0

受信時の情報取得はXHRオブジェクトから行います。event.targetにXHRオブジェクトが渡されるのでそれを使っても同じです。

oReq.onload = function(event) {
  xhr = event.target;           // 外側のoReqと同じオブジェクト
  if (xhr.status == 200) {      // 成功時
    var arraybuffer = xhr.response;     // 受信したバイナリデータ
    // 以下成功時の処理(略)
  } else {
    // エラー処理の例(404の場合は"Cannot load (Not Found): URL"と表示)
    alert("Cannot load (" + xhr.statusText + "): " + xhr.responseURL);
}