Scala и Akka HTTP: обработка запросов данных формы - PullRequest
1 голос
/ 24 апреля 2020

Предположим, у нас есть следующий запрос:

curl --location --request POST 'localhost:8080/api' \
--header 'Content-Type: multipart/form-data' \
--form 'field1=value1' \
--form 'field2=value2'

Приведенный ниже обработчик запроса получает всю сущность, но я пытаюсь понять, как вместо этого получить value1 и value2.

val requestHandler: Flow[HttpRequest, HttpResponse, _] = Flow[HttpRequest].mapAsync(1) {
  case HttpRequest(HttpMethods.POST, Uri.Path("/api"), _, entity, _) =>
    val entityTextFuture: Future[String] = entity.toStrict(3 seconds).map(_.data.utf8String)
      entityTextFuture.flatMap { text =>
        Future(HttpResponse(
          StatusCodes.OK,
          entity = text
        ))
      }
}

Важно : Мне нужно использовать серверный API-интерфейс низкого уровня Akka HTTP, поэтому я не могу использовать маршруты.

Большое спасибо за ваше время и помощь заранее!

1 Ответ

1 голос
/ 28 апреля 2020

Если все, что вам нужно, это строковые значения в данных формы, вам просто нужно разархивировать до StrictForm, а затем разархивировать каждое из значений поля в виде строк.

Вот подтверждение концепции Ammonite script который отвечает на ваш запрос curl с value1 & value2:

import $ivy.`com.typesafe.akka::akka-actor:2.6.3`
import $ivy.`com.typesafe.akka::akka-stream:2.6.3`
import $ivy.`com.typesafe.akka::akka-http:10.1.11`

import scala.concurrent.Future

import akka.actor.ActorSystem
import akka.stream.scaladsl.Flow
import akka.http.scaladsl.Http
import akka.http.scaladsl.model._
import akka.http.scaladsl.unmarshalling.Unmarshal
import akka.http.scaladsl.common.StrictForm

implicit val system = ActorSystem()
implicit val ec = system.dispatcher

val requestHandler: Flow[HttpRequest, HttpResponse, _] = Flow[HttpRequest].mapAsync(1) {
  case HttpRequest(HttpMethods.POST, Uri.Path("/api"), _, entity, _) =>
    for {
      strictForm <- Unmarshal(entity).to[StrictForm]
      fieldsSeq <- Future.traverse(strictForm.fields) {
        case (n, v) => Unmarshal(v).to[String].map(n -> _)
      }
      fields = fieldsSeq.toMap
      response = fields("field1") + " & " + fields("field2")
    } yield HttpResponse(StatusCodes.OK, entity = response)
}

Http().bindAndHandle(requestHandler, "localhost", 8080)
...