Как загружать файлы и получать поля формы в akka-http

#scala #akka #akka-http

#scala #akka #akka-http

Вопрос:

Я пытаюсь загрузить файл через akka-http и заставил его работать со следующим фрагментом

 def tempDestination(fileInfo: FileInfo): File =
  File.createTempFile(fileInfo.fileName, ".tmp")

val route =
  storeUploadedFile("csv", tempDestination) {
    case (metadata, file) =>      
      //Do my operation on the file.
      complete("File Uploaded. Status OK")
  }
  

Но я бы также хотел отправить param1 / param2 в опубликованной форме.

Я попробовал следующее, и это работает, но мне приходится отправлять параметры через URL (http://host:port/csv-upload?userid=arvind )

 (post amp; path("csv-upload")) {
   storeUploadedFile("csv", tempDestination) {
     case (metadata, file) =>
       parameters('userid) { userid =>
          //logic for processing the file
          complete(OK)
       }
   }
}
    
  

Ограничение на размер файла составляет около 200-300 МБ. Я добавил следующее свойство в свой conf

  akka{
     http{
         parsing{
             max-content-length=200m
         }
     }
 }
  

Есть ли способ, которым я могу получить параметры с помощью formFields директивы?

Я попробовал следующее

 fileUpload("csv") {
        case (metadata, byteSource) =>
          formFields('userid) { userid =>
            onComplete(byteSource.runWith(FileIO.toPath(Paths.get(metadata.fileName)))) {
              case Success(value) =>
                logger.info(s"${metadata}")
complete(StatusCodes.OK)
              case Failure(exception) =>
                complete("failure")
                
  

Но с помощью приведенного выше кода я столкнулся со следующим исключением

 java.lang.IllegalStateException: Substream Source cannot be materialized more than once
    at akka.stream.impl.fusing.SubSource$$anon$13.setCB(StreamOfStreams.scala:792)
    at akka.stream.impl.fusing.SubSource$$anon$13.preStart(StreamOfStreams.scala:802)
    at akka.stream.impl.fusing.GraphInterpreter.init(GraphInterpreter.scala:306)
    at akka.stream.impl.fusing.GraphInterpreterShell.init(ActorGraphInterpreter.scala:593)

  

Спасибо,
Арвинд

Комментарии:

1. Если вы хотите отправить файл некоторые данные в теле запроса, посмотрите, multipart/-form data у вас есть это сообщение об ошибке, потому что fileUpload использует тело запроса, и когда formFields пытается прочитать тело запроса, читать нечего (тело уже было использовано (в виде потока) fileUpload )

2. Понял. Я попробую добавить пользовательский процессор для multipart/form-data и попытаюсь использовать файловый поток отдельно, а строковые параметры отдельно.

Ответ №1:

Я получил это, работая с чем-то вроде:

   path("upload") {

    formFields(Symbol("payload")) { payload =>
      println(s"Server received request with additional payload: $payload")

      def tempDestination(fileInfo: FileInfo): File = File.createTempFile(fileInfo.fileName, ".tmp.server")

      storeUploadedFile("binary", tempDestination) {
        case (metadataFromClient: FileInfo, uploadedFile: File) =>
          println(s"Server stored uploaded tmp file with name: ${uploadedFile.getName} (Metadata from client: $metadataFromClient)")
          complete(Future(FileHandle(uploadedFile.getName, uploadedFile.getAbsolutePath, uploadedFile.length())))
      }
    }
  }
  

Полный пример:
https://github.com/pbernet/akka_streams_tutorial/blob/master/src/main/scala/akkahttp/HttpFileEcho.scala