Akka-HTTP: file download

I am trying to implement a simple file upload using akka http. My attempt is as follows:

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")) } 

There are several problems with this code:

  • Files larger than the configured object size cannot be loaded: Request Content-Length 24090745 exceeds the configured limit of 8388608
  • Performing two downloads per line dead letters encountered. exception dead letters encountered. .

What is the best way to overcome size limits and how can I close a file so that subsequent download overwrites the existing file (ignoring the simultaneous download at the moment)?

+6
source share
2 answers

For point 2, I believe that source.to(sink).run() performs the operation asynchronously. He materializes Future . Therefore, your HTTP request may return before the file is written, so if you start the second download on the client, as soon as the first request returns, the first one may not have finished writing to the file.

You can use the onComplete or onSuccess only to complete the HTTP request when the future ends:

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:

For content length issues, you can increase the size of this property in application.conf . Default:

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

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

+8
source

To summarize the comments of mattinbits, the follwing solution works:

  • Increase akka.server.parsing.max-content-length
  • Using onSuccess

Here is the code snippet:

 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)) } } } } 
+5
source

All Articles