akka HttpResponse 将正文读取为字符串 scala

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/32315789/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-22 07:32:17  来源:igfitidea点击:

akka HttpResponse read body as String scala

scalaakkaakka-http

提问by tg44

So I have a function with this signature (akka.http.model.HttpResponse):

所以我有一个带有这个签名的函数(akka.http.model.HttpResponse):

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

I simply get a value in a test like:

我只是在测试中得到一个值,例如:

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

I want to check its body in a test something like:

我想在测试中检查它的身体,例如:

resp.entity.asString == "tags"

My question is how I can get the response body as string?

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

采纳答案by user3548738

import akka.http.scaladsl.unmarshalling.Unmarshal

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

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

回答by Konrad 'ktoso' Malawski

Since Akka Http is streams based, the entity is streaming as well. If you really need the entire string at once, you can convert the incoming request into a Strictone:

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

This is done by using the toStrict(timeout: FiniteDuration)(mat: Materializer)API to collect the request into a strict entity within a given time limit (this is important since you don't want to "try to collect the entity forever" in case the incoming request does actually never end):

这是通过使用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`

回答by Shashank Jain

You can also try this one also.

你也可以试试这个。

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

回答by J. Nadberezny

Unmarshaller.stringUnmarshaller(someHttpEntity)

works like a charm, implicit materializer needed as well

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

回答by Shendor

Unfortunately in my case, Unmarshalto String didn't work properly complaining on: Unsupported Content-Type, supported: application/json. That would be more elegant solution, but I had to use another way. In my test I used Future extracted from entity of the response and Await (from scala.concurrent) to get the result from the Future:

不幸的是,在我的情况下,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)
}

If you need to go through all lines in a response, you can use runForeachof Source:

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

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

回答by Alexander Kondaurov

Here is simple directive that extracts stringfrom request's body

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

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

回答by u5827450

Here is my working example,

这是我的工作示例,

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


  }