如何获得akka.http.scaladsl.model.HttpRequest正文?

时间:2017-03-17 15:33:48

标签: scala akka-http

我正在使用akka-http并为我的某个课程编写Unmarhsaller。我想要做的是将POST请求的主体作为String,以便我可以用它创建我的对象:

case class MyClass(geom: String)

implicit def fromRequestUnmarshaller = Unmarshaller[HttpRequest, MyClass]({implicit ec: ExecutionContext =>
    req: HttpRequest => Future(MyClass(req.entity.asInstanceOf[HttpEntity.Strict].data.map(_.toChar).mkString))
})

这似乎是一个非常复杂的代码行,只是为了让身体成为String。另外,我正在做一个非常丑陋的asInstanceOf[HttpEntity.Strict]因为我在调试时认为HttpRequest属于这种类型。

我的问题:是否有更简单/更清洁的方式来实现我的目标?

非常感谢:)

1 个答案:

答案 0 :(得分:3)

小心

akka将实体实现为Source[ByteString,_]的原因是因为HttpRequest的实体可能是无限长度的。因此,您最好确保您的应用程序有足够的RAM来处理可能被抛出的任何请求......

<强> toStrict

您可以使用HttpEntity#toStrict

implicit val materializer : Materializer = ???
implicit val executionContext : ExecutionContext = ???    

val entityFromRequest : (HttpRequest, FiniteDuration) => Future[ByteString] = 
  (_ : HttpRequest)
    .entity 
    .toStrict(_ : FiniteDuration)
    .map(_.data)

手动转换

您可以将HttpRequest的“body”(即实体)作为Source[ByteString, _]访问:

val getBodySource : HttpRequest => Source[ByteString,_] = 
  _.entity
   .dataBytes

然后可以将此来源发送到一个接收器,该接收器会将ByteString值收集到Seq中:

val convertSrcToSeq : Source[ByteString,_] => Future[Seq[ByteString]] = 
  _ runWith Sink.seq

您正在寻找的是一个连续的String,因此需要将这些ByteStrings缩减为单个值:

val reduceSeqToStr : Future[Seq[ByteString]] => Future[ByteString] = 
  _ map (_ reduceOption (_ ++ _) getOrElse ByteString.empty)

现在可以将这些步骤组合成一个函数:

val getBodyStrFromRequest : HttpRequest => Future[ByteString] = 
  getBodySource andThen convertSrcToSeq andThen reduceSeqToStr