【问题标题】:Akka-Http File Upload sending response before request is completely readAkka-Http 文件上传在请求被完全读取之前发送响应
【发布时间】:2018-02-09 19:38:26
【问题描述】:

我的 akka-http 服务器中有以下路由:

def tempDestination(fileInfo: FileInfo): File = {
    log.info(s"File info for upload: [$fileInfo]")
    File.createTempFile(fileInfo.fileName, ".tmp")
}
...
post {
    log.info("Inside the file upload path")
    fileUpload("zip") {
      case (fileInfo, bytes) =>
        val dest = tempDestination(fileInfo)
        val uploadedF: Future[(FileInfo, File)] =
          bytes
            .runWith(FileIO.toPath(dest.toPath))
            .map(_ => (fileInfo, dest))

        onSuccess(uploadedF) { (info, file) =>
            val fileCreated: Future[MyFile] = (fileRegistryActor ? NewFile(file)).mapTo[MyFile]
            complete((StatusCodes.Created, fileCreated))
        }
    }
}

通过表单将文件上传到这里后,我在日志中看到了这一点:

Sending an 2xx 'early' response before end of request was received... Note that the connection will be closed after this response. Also, many clients will not read early responses! Consider only issuing this response after the request data has been completely read!

我认为uploadedF Future 在创建并完成 Sink 的 IOResult 之前不会完成。我错过了什么?确定我的整个请求是否已被读取并且我的文件是否已完全写入磁盘的正确机制是什么?

【问题讨论】:

  • 嗯,你可能有太多的未来,试试 runWith().flatmap()
  • 在底部的 fileCreated 也是一个未来,所以你可能想要映射它(就像你使用uploadedF 一样)以便调用完成
  • 如果我runWith().flatMap(),那么我的身体需要返回一个Future[(FileInfo, File)],而不仅仅是我拥有的(FileInfo, File)。我可以尝试映射 fileCreated 未来,但通过查看预制模板,使用 Future 调用 complete() 是可行的,并且在解决 Future 后完成。
  • 另外,如果我映射到 fileCreated,那么我需要专门等待未来,因为 onSuccess 的返回需要是 Route 而不是 Future[Route]
  • 到目前为止,onSuccess 的主体只被一个成功的IOResult 调用。我认为问题是文件在请求完成之前被写入磁盘,我只是在等待文件,而不是请求。

标签: scala akka-http


【解决方案1】:

所以似乎对我来说解决这个问题的方法是将路由从 post 更改为 post & extractRequest

def tempDestination(fileInfo: FileInfo): File = {
    log.info(s"File info for upload: [$fileInfo]")
    File.createTempFile(fileInfo.fileName, ".tmp")
}
...
(post & extractRequest) { _ =>
    log.info("Inside the file upload path")
    fileUpload("zip") {
      case (fileInfo, bytes) =>
        val dest = tempDestination(fileInfo)
        val uploadedF: Future[(FileInfo, File)] =
          bytes
            .runWith(FileIO.toPath(dest.toPath))
            .map(_ => (fileInfo, dest))

        onSuccess(uploadedF) { (info, file) =>
            val fileCreated: Future[MyFile] = (fileRegistryActor ? NewFile(file)).mapTo[MyFile]
            complete((StatusCodes.Created, fileCreated))
        }
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-06
    • 1970-01-01
    • 1970-01-01
    • 2015-09-01
    • 2019-02-06
    • 2011-10-04
    相关资源
    最近更新 更多