2015-10-03 18 views
6

私はakka httpを使って簡単なファイルアップロードを実装しようとしています。 次のように私の試みはなりますAkka-HTTP:ファイルアップロード

import akka.actor.ActorSystem 
    import akka.event.{LoggingAdapter, Logging} 
    import akka.http.scaladsl.Http 
    import akka.http.scaladsl.model.{HttpResponse, HttpRequest} 
    import akka.http.scaladsl.model.StatusCodes._ 
    import akka.http.scaladsl.server.Directives._ 
    import akka.stream.{ActorMaterializer, Materializer} 
    import com.typesafe.config.Config 
    import com.typesafe.config.ConfigFactory 
    import scala.concurrent.{ExecutionContextExecutor, Future} 
    import akka.http.scaladsl.model.StatusCodes 
    import akka.http.scaladsl.model.HttpEntity 
    import java.io._ 
    import akka.stream.io._ 

    object UploadTest extends App { 
     implicit val system = ActorSystem() 
     implicit val executor = system.dispatcher 
     implicit val materializer = ActorMaterializer() 

     val config = ConfigFactory.load() 
     val logger = Logging(system, getClass) 

     val routes = { 
     pathSingleSlash { 
      (post & extractRequest) { 
      request => { 
       val source = request.entity.dataBytes 
       val outFile = new File("/tmp/outfile.dat") 
       val sink = SynchronousFileSink.create(outFile) 
       source.to(sink).run() 
       complete(HttpResponse(status = StatusCodes.OK)) 
      } 
      } 
     } 
     } 

     Http().bindAndHandle(routes, config.getString("http.interface"), config.getInt("http.port")) 

    } 

このコードのいくつかの問題があります。

  1. が設定されたエンティティのサイズよりも大きいファイルをアップロードすることができません。 Request Content-Length 24090745 exceeds the configured limit of 8388608
  2. が行に2本のアップロードを実行しますdead letters encountered.例外が発生します。

サイズの制限を克服する最良の方法は何ですか。また、後でアップロードしたファイルが既存のファイルを上書きするようにファイルを正しく閉じるにはどうすればよいですか?

答えて

8

ポイント2については、source.to(sink).run()が動作を非同期に実行すると思います。それはFutureを具体化する。したがって、ファイルの書き込みが完了する前にHTTPリクエストが返される可能性があるため、最初のリクエストが返されるとすぐにクライアントで2回目のアップロードを開始すると、最初のリクエストがファイルへの書き込みを完了していない可能性があります。将来が完了したときに

は、あなただけのhttpリクエストを完了するために、onCompleteまたはonSuccessディレクティブを使用することができます。

http://doc.akka.io/docs/akka-stream-and-http-experimental/1.0-M2/scala/http/directives/alphabetically.html

http://doc.akka.io/docs/akka-stream-and-http-experimental/1.0/scala/http/routing-dsl/directives/future-directives/onSuccess.html

EDIT:コンテンツの長さの問題については

、1あなたができることは、そのプロパティのサイズをapplication.confに増やすことです。デフォルトは次のとおりです。

akka.server.parsing.max-content-length = 8m 

http://doc.akka.io/docs/akka-stream-and-http-experimental/1.0/java/http/configuration.html

+0

ありがとうございます。onSuccessを使用すると、「dead letters encountered」問題が解決します。 –

+0

他の問題のアイデアを追加した編集を追加しました – mattinbits

+0

こんにちは、 max-content-lengthを大きな値に設定しても、コンテンツ全体がメモリにバッファされているわけではありません。これはこれを解決する安全な方法です。私はあなたの答えをupvotedだろうが、私は十分なクレジットを持っていない: - ( –

5

がmattinbitsコメントをまとめる参照してください、follwingソリューションが動作します。

  1. onSuccess

を使用してakka.server.parsing.max-content-length

  • を増やすここでの抜粋ですコード:

    val routes = { 
        pathSingleSlash { 
        (post & extractRequest) { 
         request => { 
         val source = request.entity.dataBytes 
         val outFile = new File("/tmp/outfile.dat") 
         val sink = SynchronousFileSink.create(outFile) 
         val repl = source.runWith(sink).map(x => s"Finished uploading ${x} bytes!") 
         onSuccess(repl) { repl => 
          complete(HttpResponse(status = StatusCodes.OK, entity = repl)) 
         } 
         } 
        } 
        } 
    
  • 関連する問題