Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/jsf-2/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala Akka HTTP:文件上载_Scala_Upload_Akka_Akka Stream - Fatal编程技术网

Scala Akka HTTP:文件上载

Scala Akka HTTP:文件上载,scala,upload,akka,akka-stream,Scala,Upload,Akka,Akka Stream,我正在尝试使用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.mo

我正在尝试使用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"))

    }
此代码有几个问题:

  • 无法上载大于所配置实体大小的文件:
    请求内容长度24090745超过配置的限制8388608
  • 在一行中执行两次上载会导致遇到死信。异常

  • 克服大小限制的最佳方法是什么?如何正确关闭文件,以便后续上载将覆盖现有文件(暂时忽略并发上载)?

    对于第2点,我认为
    source.to(sink).run()
    会自动执行操作。它实现了
    未来
    。因此,您的HTTP请求可能在文件写入完成之前返回,因此,如果您在第一个请求返回后立即在客户端启动第二次上载,则第一个请求可能尚未完成对文件的写入

    您可以使用
    onComplete
    onSuccess
    指令仅在将来完成时完成http请求:

    编辑:

    对于内容长度问题,您可以在
    application.conf
    中增加该属性的大小。默认值为:

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

    参见

    总结mattinbits的评论,以下解决方案有效:

  • 增加akka.server.parsing.max内容长度
  • 使用
    onSuccess
  • 下面是一段代码:

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

    谢谢,使用onSuccess解决了“遇到死信”的问题。我添加了一个编辑,其中包含了解决其他问题的想法。谢谢,我了解到,将“最大内容长度”设置为更大的值并不意味着整个内容都在内存中缓冲。所以这是解决这个问题的安全方法。我本来会投票给你的答案,但我没有足够的学分:-(我想你可以接受它作为答案…)