akka HttpResponse 将正文读取为 String scala

Posted

技术标签:

【中文标题】akka HttpResponse 将正文读取为 String scala【英文标题】:akka HttpResponse read body as String scala 【发布时间】:2015-11-25 18:08:52 【问题描述】:

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

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

【问题讨论】:

相关:***.com/q/31532838/390708 你在使用akka-http-testkit吗?如果是的话,你可以在测试中使用entityAs[String]来获取body作为String值。 我需要使用 PlaySpec 所以我不能使用 akka-http-testkit :( 我注意到如果将 akka-http-circe 的 FailFastCirceSupport (1.22.0) 带入上下文,entityAs[String] 将不起作用。解决方法是移动导入。 【参考方案1】:
import akka.http.scaladsl.unmarshalling.Unmarshal

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

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

【讨论】:

您使用的是哪个 akka-http-core 版本?对于 2.4.6,我在任何地方都找不到 akka.http.scaladsl.unmarshalling @akauppi 这是akka-http-experimental 不是akka-http-core 不幸的是 Unmarshal 生活在 akka-http 工件中(不是 akka-http-coreakka-http-client)。 认为应该是 ActorMaterializer() 而不是 ActorFlowMaterializer()?【参考方案2】:

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

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

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

【讨论】:

【参考方案3】:

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

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

【讨论】:

【参考方案4】:
Unmarshaller.stringUnmarshaller(someHttpEntity)

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

【讨论】:

【参考方案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")
    


  

【讨论】:

参考:doc.akka.io/docs/akka-http/current/client-side/…【参考方案6】:

你也可以试试这个。

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

【讨论】:

【参考方案7】:

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

【讨论】:

这似乎是一个好方法,但你使用的是哪种隐式 FlowMaterializer? (你是从导入中得到它还是使用一些默认实现?) 您可以只创建一个临时实例或重新使用现有实例,我修改了我的回复。 我认为解组器是执行此操作的最新方法,因此我重新分配了答案标记。 我想两者都可以。干杯 哇,为什么是超时和必需的参数?让它使用起来更复杂和麻烦的方法..明智的默认会好得多。

以上是关于akka HttpResponse 将正文读取为 String scala的主要内容,如果未能解决你的问题,请参考以下文章

Akka HTTP:如何将 Json 格式响应解组为域对象

HttpContext 上的管道

如何在 Akka HTTP 中将“text/plain”解组为 JSON

akka http 抛出 EntityStreamException:实体流截断

Akka(38): Http:Entityof ByteString-数据传输基础

读取 HttpResponse