Подтвердить что ты не робот

Akka HttpResponse читает тело как String scala

Итак, у меня есть функция с этой сигнатурой (akka.http.model.HttpResponse):

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

Я просто получаю значение в тесте, например:

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

Я хочу проверить его тело в тесте что-то вроде:

resp.entity.asString == "tags"

Мой вопрос в том, как я могу получить тело ответа как строку?

4b9b3361

Ответ 1

  import akka.http.scaladsl.unmarshalling.Unmarshal


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

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

Ответ 2

Так как Akka Http основан на потоках, объект также работает. Если вам действительно нужна вся строка сразу, вы можете преобразовать входящий запрос в Strict one:

Это делается с помощью API toStrict(timeout: FiniteDuration)(mat: Materializer) для сбора запроса в строгий объект в течение заданного срока (это важно, поскольку вы не хотите "пытаться собирать объект навсегда" в случае, если входящий запрос на самом деле никогда не заканчивается):

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`

Ответ 3

Вы также можете попробовать это.

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

Ответ 4

К сожалению, в моем случае Unmarshal для String не работал должным образом, жалуясь на: Unsupported Content-Type, supported: application/json. Это было бы более элегантное решение, но мне пришлось использовать другой способ. В моем тесте я использовал Future, извлеченный из объекта ответа и Await (из scala.concurrent), чтобы получить результат из Будущего:

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

Если вам нужно пройти все строки в ответе, вы можете использовать runForeach для источника:

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

Ответ 5

Вот мой рабочий пример,

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


  }

Ответ 6

Unmarshaller.stringUnmarshaller(someHttpEntity)

работает как шарм, нужен неявный материализатор

Ответ 7

Вот простая директива, которая извлекает string из тела запроса

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