如何获取akka.http.scaladsl.model.HttpRequest的请求体?

3

我正在使用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))
})

似乎只是为了获取正文字符串而编写了非常复杂的代码。此外,我正在进行一个非常丑陋的asInstanceOf [HttpEntity.Strict],仅因为我在调试时发现HttpRequest是这种类型。

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

非常感谢 :)

1个回答

3

注意

akka将Http请求中的实体(entity)实现为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)

手动转换

你可以通过 Source[ByteString, _] 来访问 HttpRequest 的实体(即 "body"):

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

源可以被发送到一个汇点,该汇点将 ByteString 值收集到一个 Seq 中:

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

您要查找的实体是一个连续的字符串,因此这些字节字符串需要被缩减为单个值:
val reduceSeqToStr : Future[Seq[ByteString]] => Future[ByteString] = 
  _ map (_ reduceOption (_ ++ _) getOrElse ByteString.empty)

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

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

有没有办法确保实体长度是有限的? - meucaa
@meucaa 你无法阻止客户端发送无限长度的数据。但是你可以修改 getBodySource 函数来限制处理的 ByteString 值的数量,或者创建一个略微复杂一些的 Source[ByteString, _] 来限制请求体中字符的数量... - Ramón J Romero y Vigil
@meucaa 你也可以检查 HttpRequest,使用模式匹配来确定请求体是否是严格的,并在实体不是严格的情况下返回404响应。 - Ramón J Romero y Vigil
好的,谢谢你的回答。我简直不敢相信这样一个常见的操作会如此复杂。是啊,我可以使用模式匹配来创建我的任意转换的干净版本。 - meucaa
@meucaa 不用谢。问题的复杂性源于http协议没有对请求/响应实体施加此类限制。因此,akka必须提供符合规范的功能。这既是优点也是缺点...祝你编程愉快。 - Ramón J Romero y Vigil

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接