akka HttpResponse read body as String scala

前端 未结 7 955
广开言路
广开言路 2020-12-28 13:27

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

def apply(query: Seq[(String, String)], accept: String): HttpResponse
相关标签:
7条回答
  • 2020-12-28 14:03
    import akka.http.scaladsl.unmarshalling.Unmarshal
    
    implicit val system = ActorSystem("System")  
    implicit val materializer = ActorFlowMaterializer() 
    
    val responseAsString: Future[String] = Unmarshal(entity).to[String]
    
    0 讨论(0)
  • 2020-12-28 14:03

    Here is simple directive that extracts string from request's body

    def withString(): Directive1[String] = {
      extractStrictEntity(3.seconds).flatMap { entity =>
        provide(entity.data.utf8String)
      }
    }
    
    0 讨论(0)
  • 2020-12-28 14:09

    Unfortunately in my case, Unmarshal to 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:

    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 runForeach of Source:

     response.entity.dataBytes.map(_.utf8String).runForeach(data => println(data))
    
    0 讨论(0)
  • 2020-12-28 14:09

    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")
        }
    
    
      }
    
    0 讨论(0)
  • 2020-12-28 14:14

    You can also try this one also.

    responseObject.entity.dataBytes.runFold(ByteString(""))(_ ++ _).map(_.utf8String) map println
    
    0 讨论(0)
  • 2020-12-28 14:23

    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 Strict one:

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

    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`
    
    0 讨论(0)
提交回复
热议问题