まじめなことを書くつもりでやっています。 適当なことは 「一角獣は夜に啼く」 に書いています。
この広告は、90日以上更新していないブログに表示しています。
Web ブラウザから web サーバーに HTTP リクエストを送る際によく用いられるXMLHttpRequest (XHR) ですが、XMLHttpRequest のAPI を見ると、chunked transfer encoding による HTTP のストリーミングからのデータを受信して、都度処理をしていく、というような使い方ができるようにはなっていないと思います。
Internet Explorer 10 (IE 10) では、そういうことができるように拡張された XMLHttpRequest が実装されています ので紹介します。
もちろん、通常のXMLHttpRequest でも chunked transfer encoding なデータを受け取ることはできますし、データの受信が進むたびに progress イベントが発生しますので、受け取るデータが少量の場合はなんとかなります。 詳しくは以下のページをご覧ください。
しかしながら、受け取ったデータはXMLHttpRequest の接続が終了するまでXMLHttpRequest オブジェクトの中にため続けられますので、長時間 HTTP 接続を保ったまま、送られてきたデータを都度処理していく というようなことができません。 データがどんどんたまっていきますので、やがてメモリ不足になってしまいます。
具体的には、Twitter が Streaming API を chunked transfer encoding で送ってきます ので、XMLHttpRequest でTwitter StreamingAPI を扱いたい場合に困りますね。
まあ普通のブラウザ上でTwitter の StreamingAPI なんて使えなくてもいいでしょ、って感じもしますが、最近はブラウザの拡張機能やら Windows ストアアプリ (旧称 Metro アプリ) やらでJavaScript からTwitter StreamingAPI を使いたくなることがしばしばあります。 というわけで、Windows ストアアプリをJavaScript で書くときに使える IE 10 の拡張されたXMLHttpRequest を使って、chunked transfer encoding で送られてきたデータを都度処理していく方法について書いておきます。
HTTP ストリーミングを扱うためには、リクエストを送る前に、XMLHttpRequest#responseType プロパティに "ms-stream" を設定します。
ダウンロード要求の responseType プロパティが "ms-stream" に設定されている場合、次の例に示すように、実行中にコンテンツを操作できます。
http://msdn.microsoft.com/ja-jp/library/ie/hh673569%28v=vs.85%29.aspx
次に、レスポンスの受け取り方について説明します。 readyStateChange イベントでXMLHttpRequest#readyState プロパティがXMLHttpRequest.LOADING になったときにストリーミングを受け取れるようになっていますので、その中でストリーミングの処理を開始します。 ストリーミングで受け取ったデータは、XMLHttpRequest#response プロパティの値に入っている MSStream オブジェクトで表されます。
MSStream オブジェクトは、Windows.Storage.Streams.IInputStream インターフェイスを実装したオブジェクト (IInputStream オブジェクト) をラップしたもので、実際のストリームは IInputSteram オブジェクトで表されます。
MSStream オブジェクトからデータを読み出す方法としてはMSStreamReader を使う方法もありますが、どうやら MSStreamReader ではデータを受信する都度データを読み出す、というようなことができない (すべてのデータを読み込んでから最後に読み出すしかできない) ようだったので、MSStream オブジェクトではなく、その下にある IInputStream オブジェクトを直接操作してデータを読み出すしかなさそうです。
MSStream のドキュメントにはMSStream#msInputStream プロパティ というものが存在しますが、手元 (Windows 8RTM 版) で試したところそのようなプロパティは存在せず、代わりに MSStream#msDetachStream メソッドというのが存在しました。 このメソッドを使うと、MSStream オブジェクトとその下にある IInputStream オブジェクトが切り離され、切り離された IInputStream オブジェクトを返り値として得ることができます。IInputStream オブジェクトの readAsync メソッド を使うことで*1、データを受け取るたびにデータの読み出しを行って処理を進めることができます。
Windows ストアアプリ開発時に使えるサンプルコードとして、WinJS.xhr (XMLHttpRequest を扱う便利関数) で HTTP ストリーミングを扱う例を示します。
varuri ="http://www.example.com/test_stream";WinJS.xhr({ url:uri, responseType:"ms-stream"}).then(function (req){// 完了したときの処理// ...},function onError(err){// エラーが発生した時の処理// ...},function onProg(req){// streaming の読み込みを開始した時に以下の if 文の中に入るif (req.readyState === req.LOADING){// res は MSStream オブジェクトvar res = req.response;// msDetachStream メソッドを呼び出すことで IInputStream オブジェクトを res から切り離して取り出すvar stream = res.msDetachStream();// さらに stream からデータを読み込む処理に移る// ...}}).done(null,function (err){// 例外発生時の処理// ...});
JavaScript でTCP/IP 上のストリーミングを扱うならば、HTTP の chunked transfer encoding を使うよりも以下の 2 つのどちらかを使う方が便利な気がします。Twitter StreamingAPI のようにサーバー側がすでに存在している場合はどうしようもないですが、新たに (サーバー側も含めて )Twitter StreamingAPI みたいなものを実装するのであれば、Server-Sent Events を使うのが良さそうです。
*1:もしくは IInputStream からデータを読み出すためのオブジェクトを操作することで
引用をストックしました
引用するにはまずログインしてください
引用をストックできませんでした。再度お試しください
限定公開記事のため引用できません。