37

所以我有一个带有这个签名的函数(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"

我的问题是如何将响应正文作为字符串获取?

4

7 回答 7

40
import akka.http.scaladsl.unmarshalling.Unmarshal

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

val responseAsString: Future[String] = Unmarshal(entity).to[String]
于 2016-04-10T20:03:13.610 回答
30

由于 Akka Http 是基于流的,因此实体也是流式的。如果您真的需要一次整个字符串,您可以将传入的请求转换为Strict一个:

这是通过使用toStrict(timeout: FiniteDuration)(mat: Materializer)API 在给定的时间限制内将请求收集到严格的实体中来完成的(这很重要,因为您不想“尝试永远收集实体”,以防传入的请求实际上永远不会结束):

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`
于 2015-09-01T08:47:21.393 回答
12

你也可以试试这个。

responseObject.entity.dataBytes.runFold(ByteString(""))(_ ++ _).map(_.utf8String) map println
于 2017-07-27T03:15:47.753 回答
5
Unmarshaller.stringUnmarshaller(someHttpEntity)

像魅力一样工作,也需要隐含的物化器

于 2018-07-11T12:32:26.390 回答
5

这是string从请求正文中提取的简单指令

def withString(): Directive1[String] = {
  extractStrictEntity(3.seconds).flatMap { entity =>
    provide(entity.data.utf8String)
  }
}
于 2019-05-06T11:33:13.943 回答
3

不幸的是,在我的情况下,Unmarshalto String 无法正常工作,抱怨:Unsupported Content-Type, supported: application/json。那将是更优雅的解决方案,但我不得不使用另一种方式。在我的测试中,我使用从响应实体中提取的 Future 和 Await(来自 scala.concurrent)从 Future 中获取结果:

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

如果您需要遍历响应中的所有行,可以使用runForeachSource:

 response.entity.dataBytes.map(_.utf8String).runForeach(data => println(data))
于 2016-12-30T16:36:32.290 回答
1

这是我的工作示例,

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


  }
于 2018-06-28T21:18:56.497 回答