(JavaScriptでの)バイナリデータの送信と受信


JavaScript バイナリ」でググっても古い情報ばかり見つかるので、ついカッとなって勢いで翻訳しました。
多分精度は低いのでおかしい所は指摘を頂けると嬉しいです。すぐ直します、恥ずかしいので。

初めに追記 (2013/04/27)

本家の方に翻訳文を移しました。↓こちらの文章の方が精度が高いのでお勧めです。

JavaScript の Typed Array を使ってバイナリデータを受信する

XMLHttpRequest オブジェクト の responseType プロパティに設定する事で、サーバに期待する応答が変更できます。設定可能な値は、空の文字列(デフォルト)、"arraybuffer" 、"blob"、"document"、"json"、"text" です。response プロパティのエンティティボディには responseType に応じて ArrayBuffer、Blob、Document、JSON、又は string が入ります。要求が未完了、又は成功しないと null になります。

この例では、バイナリファイルとして画像を読み込み、生のバイト列から8ビット符号なし整数の配列を作成します。

var oReq = new XMLHttpRequest();
oReq.open("GET", "/myfile.png", true);
oReq.responseType = "arraybuffer";
 
oReq.onload = function (oEvent) {
  var arrayBuffer = oReq.response; // Note: not oReq.responseText
  if (arrayBuffer) {
    var byteArray = new Uint8Array(arrayBuffer);
    for (var i = 0; i < byteArray.byteLength; i++) {
      // do something with each byte in the array
    }
  }
};
 
oReq.send(null);

上記の方法の代わりに、Blob インターフェースを利用して arraybuffer データから直接 Blob を作成します。

var oReq = new XMLHttpRequest();
oReq.open("GET", "/myfile.png", true);
oReq.responseType = "arraybuffer";
 
oReq.onload = function(oEvent) {
  var blob = new Blob([oReq.response], {type: "image/png"});
  // ...
};
 
oReq.send();

また、responseType プロパティに "blog" 文字列をセットする事で、Blob としてバイナリファイルを読む事が出来ます。

var oReq = new XMLHttpRequest();
oReq.open("GET", "/myfile.png", true);
oReq.responseType = "blob";
 
oReq.onload = function(oEvent) {
  var blob = oReq.response;
  // ...
};
 
oReq.send();

古いブラウザでバイナリデータを受信する

下に示す load_binary_resource() 関数は、指定した URL からロードしたバイナリデータを呼び元に返します。

function load_binary_resource(url) {
  var req = new XMLHttpRequest();
  req.open('GET', url, false);
  //XHR binary charset opt by Marcus Granado 2006 [http://mgran.blogspot.com]
  req.overrideMimeType('text\/plain; charset=x-user-defined');
  req.send(null);
  if (req.status != 200) return '';
  return req.responseText;
}

5行目に魔法がかかっていて、MIME type を上書きする事でブラウザに user-defined character set の plain text として扱う事を強制します。これによりブラウザにパースさせずバイト列を未処理のまま通します。

var filestream = load_binary_resource(url);
var abyte = filestream.charCodeAt(x) & 0xff; // throw away high-order byte (f7)

上記の例では、読み込んだバイナリデータのオフセット x のバイトを取得します。x の有効範囲は 0 〜 filestream.length - 1 です。

詳しい説明は http://mgran.blogspot.jp/2006/08/downloading-binary-streams-with.html を見て下さい。あとこちらも。Downloading Files | MDN

バイナリデータを送信する

XMLHttpRequest の send はバイナリデータを簡単に送信できるように拡張され、ArrayBuffer, Blob, File オブジェクトを受け取る事が出来ます。

以下の例では、on-the-fly(その場) で作ったテキストファイルを POST メソッドを利用して "file" をサーバに送ります。この例は plain text ですが、バイナリファイルのデータが入っているとイメージする事も出来ます。

var oReq = new XMLHttpRequest();
oReq.open("POST", url, true);
oReq.onload = function (oEvent) {
  // Uploaded.
};
 
var blob = new Blob(['abc123'], {type: 'text/plain'});
 
oReq.send(blob);

バイナリデータとして Typed Array を送る

バイナリデータとして JavaScript typed arrays を送信することができます。

var myArray = new ArrayBuffer(512);
var longInt8View = new Uint8Array(myArray);
 
for (var i=0; i< longInt8View.length; i++) {
  longInt8View[i] = i % 255;
}
 
var xhr = new XMLHttpRequest;
xhr.open("POST", url, false);
xhr.send(myArray);

これは8ビット整数の512バイトの配列を構築し、それを送信しています。もちろんあなたの好きなように任意のバイナリデータを使用する事が出来ます。

注:XMLHttpRequestを使っての ArrayBuffer 送信のサポートは Geckoの9.0(のFirefox 9.0 / Thunderbirdの9.0 / SeaMonkeyの2.6)で追加されました。ここに他のブラウザのサポートに関する情報を追加して下さい。

送信フォームやファイルをアップロードする

この段落を読んで下さい Using XMLHttpRequest | MDN

Firefox独自の例

この例では、非同期でバイナリコンテンツを送信するのに、POST メソッドと Firefox の非標準である sendAsBinary() を使います。

var req = new XMLHttpRequest();
req.open("POST", url, true);
// set headers and mime-type appropriately
req.setRequestHeader("Content-Length", 741);
req.sendAsBinary(aBody);

4行目で Content-Length ヘッダに 741 を設定するのは、データが741バイト長であることを示します。送信するデータの実際のサイズに応じて明示的にこの値を変更する必要があります。

5行目では sendAsBinary() メソッドを使ってリクエストを初期化します。

また、nsIFileInputStream のインスタンスの send に渡す事で、バイナリコンテンツを送信出来ます。このケースではあなた自身が Content-Length をセットしてはいけません。その情報はストリームから自動で取得されます。

// Make a stream from a file.
var stream = Components.classes["@mozilla.org/network/file-input-stream;1"]
                       .createInstance(Components.interfaces.nsIFileInputStream);
stream.init(file, 0x04 | 0x08, 0644, 0x04); // file is an nsIFile instance   
 
// Try to determine the MIME type of the file
var mimeType = "text\/plain";
try {
  var mimeService = Components.classes["@mozilla.org/mime;1"]
          .getService(Components.interfaces.nsIMIMEService);
  mimeType = mimeService.getTypeFromFile(file); // file is an nsIFile instance
}
catch (oEvent) { /* eat it; just use text/plain */ }
 
// Send    
var req = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"]
                    .createInstance(Components.interfaces.nsIXMLHttpRequest);
req.open('PUT', url, false); /* synchronous! */
req.setRequestHeader('Content-Type', mimeType);
req.send(stream);

このページの貢献者: cgack, myakura, fusionchess
最終更新:: fusionchess, 2013/03/30 13:16:34
最終レビュー:: fusionchess, 2013/03/30 13:16:34
最終更新:: syu_kato, 2013/04/25 20:58:11
最終レビュー:: syu_kato, 2013/04/25 20:58:11

修正履歴