akka HttpResponse将body读取为String scala

时间:2015-08-31 16:28:44

标签: scala akka akka-http

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

我的问题是如何将响应主体作为字符串?

7 个答案:

答案 0 :(得分:23)

  import akka.http.scaladsl.unmarshalling.Unmarshal


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

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

答案 1 :(得分:22)

由于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`

答案 2 :(得分:7)

您也可以尝试这个。

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

答案 3 :(得分:1)

不幸的是,在我的情况下,Unmarshal到字符串无法正常抱怨: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)
    }

如果您需要浏览回复中的所有行,可以使用runForeach来源:

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

答案 4 :(得分: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")
    }


  }

答案 5 :(得分:1)

Unmarshaller.stringUnmarshaller(someHttpEntity)

工作就像一个魅力,也需要隐式实现器

答案 6 :(得分:0)

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

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