webentwicklung-frage-antwort-db.com.de

akka HttpResponse las body als String scala

Ich habe also eine Funktion mit dieser Signatur (akka.http.model.HttpResponse):

def apply(query: Seq[(String, String)], accept: String): HttpResponse

Ich bekomme einfach einen Wert in einem Test wie:

val resp = TagAPI(Seq.empty[(String, String)], api.acceptHeader)

Ich möchte seinen Körper in einem Test untersuchen, etwa:

resp.entity.asString == "tags"

Meine Frage ist, wie ich den Antworttext als String erhalten kann.

25
tg44
  import akka.http.scaladsl.unmarshalling.Unmarshal


  implicit val system = ActorSystem("System")  
  implicit val materializer = ActorFlowMaterializer() 

  val responseAsString: Future[String] = Unmarshal(entity).to[String]
22
user3548738

Da Akka Http auf Streams basiert, wird auch die Entität gestreamt. Wenn Sie wirklich die gesamte Zeichenfolge auf einmal benötigen, können Sie die eingehende Anforderung in eine Strict-Anweisung konvertieren:

Dazu verwenden Sie die toStrict(timeout: FiniteDuration)(mat: Materializer)-API, um die Anforderung innerhalb einer bestimmten Zeit in einer strengen Entität zu sammeln. :

import akka.stream.ActorFlowMaterializer
import akka.actor.ActorSystem

implicit val system = ActorSystem("Sys") // your actor system, only 1 per app
implicit val materializer = ActorFlowMaterializer() // you must provide a materializer

import system.dispatcher
import scala.concurrent.duration._
val timeout = 300.millis

val bs: Future[ByteString] = entity.toStrict(timeout).map { _.data }
val s: Future[String] = bs.map(_.utf8String) // if you indeed need a `String`

Sie können dieses auch probieren. 

responseObject.entity.dataBytes.runFold(ByteString(""))(_ ++ _).map(_.utf8String) map println
7
Shashank Jain

Hier ist eine einfache Anweisung, die string aus dem Hauptteil der Anfrage extrahiert

  def withString(): Directive1[String] = {
    extractStrictEntity(3.seconds).flatMap { entity =>
      provide(entity.data.utf8String)
    }
  }
1
Unmarshaller.stringUnmarshaller(someHttpEntity)

funktioniert wie ein Zauber, implizite Materializer benötigt

1
J. Nadberezny

Leider funktionierte Unmarshal to String nicht richtig und beschwerte sich über: Unsupported Content-Type, supported: application/json. Das wäre eine elegantere Lösung, aber ich musste einen anderen Weg wählen. In meinem Test habe ich Future aus Entity der Antwort und Await (von scala.concurrent) extrahiert, um das Ergebnis aus der Future zu erhalten:

Put("/post/item", requestEntity) ~> route ~> check {
      val responseContent: Future[Option[String]] =
        response.entity.dataBytes.map(_.utf8String).runWith(Sink.lastOption)

      val content: Option[String] = Await.result(responseContent, 10.seconds)
      content.get should be(errorMessage)
      response.status should be(StatusCodes.InternalServerError)
    }

Wenn Sie alle Zeilen in einer Antwort durchgehen müssen, können Sie runForeach von Source verwenden:

 response.entity.dataBytes.map(_.utf8String).runForeach(data => println(data))
1
Shendor

Hier ist mein Arbeitsbeispiel,

  import akka.actor.ActorSystem
  import akka.http.scaladsl.Http
  import akka.http.scaladsl.model._
  import akka.stream.ActorMaterializer
  import akka.util.ByteString

  import scala.concurrent.Future
  import scala.util.{ Failure, Success }

  def getDataAkkaHTTP:Unit = {

    implicit val system = ActorSystem()
    implicit val materializer = ActorMaterializer()
    // needed for the future flatMap/onComplete in the end
    implicit val executionContext = system.dispatcher

    val url = "http://localhost:8080/"
    val responseFuture: Future[HttpResponse] = Http().singleRequest(HttpRequest(uri = url))

    responseFuture.onComplete {
      case Success(res) => {
        val HttpResponse(statusCodes, headers, entity, _) = res
        println(entity)
        entity.dataBytes.runFold(ByteString(""))(_ ++ _).foreach (body => println(body.utf8String))
        system.terminate()
      }
      case Failure(_) => sys.error("something wrong")
    }


  }
0
Charlie 木匠