Lv.9 ストリーミングで徐々に出力したい [play framework2.0] [java]

    目次

  1. 目次
  2. 静的なデータの扱い方
  3. 動的に生成されるデータの扱い方
  4. メリット
  5. デメリット
  6. 実装方法
  7. アセスメント

Content-Lengthを判定する際には、レスポンスのデータをメモリにロードする必要が
あるわけで、ある程度の大きさのデータなら問題ないとして、気になるのは大きいデータの場合、
メモリにロードするって大丈夫なんだろうか。
いや、大丈夫じゃない。

目次

静的なデータの扱い方

playではちゃんとヘルパーを用意してくれているとのことなので、わりかし簡単でした。
よかったー。

public static Result index() {
  // ファイル名からContent-Typeを勝手に判断してくれる
  return ok(new java.io.File("/tmp/fileToServe.pdf"));
}

上記のコードでは、Content-Dispositionも追記してくれるらしい。
デフォルトではダウンロードするような記述を追記してくれる。

Content-Disposition: attachment; filename=fileToServe.pdf.

こんな感じで。

動的に生成されるデータの扱い方

理系学生日記さんに解説がありました。感謝。ひよこの絵が激しくかわいい、、、。

動的な場合は、(playに限らず)Chunked transfer encoding※を使わないといけないらしい。
Content-Lengthの代わりに、Transfer-Encodingを使うことになる。

メリット

こうすることで、動的なデータが全て生成される前に、送信可能になったデータから順繰りと
クライアントに返すことができる模様。

デメリット

ただし、どのくらい大きいのか、最終的なデータサイズは生成が終わらないと分からない
ので、プログレスバーや「あと何秒」みたいな表記が適切に表示されないというデメリットもある。

実装方法

方法としては3種類が公式ドキュメントには載ってました。
・InputStream
・String
・byte[]
のいづれかで動的に生成されるデータを扱うらしい。

(Stringの場合)

public static Result index()
{
 // Prepare a chunked text stream
 Chunks<String> chunks = new StringChunks()
 {
  // Called when the stream is ready
  public void onReady(Chunks.Out<String> out)
  {
  for (int i = 0; i < 1000; i++)
  {
   out.write("あ");
   out.write("い");
   out.write("う");
   out.write("え");
   out.write("お!");
  }
  out.close();
  }
 };
 return ok(chunks);
}

一応動いた。

※onReadyメソッドは、ストリームが送信可能になったタイミングで実行されるっぽい。

たしかに通常の出力方法に比べて、徐々に出力されていたので、ちゃんと動いたんだと思う!
・今回のplay framework2.0の動画。

質問やご指摘など募集中です

(マークダウン記法使えます)