我正在使用Spray查询REST端点,该端点将返回大量数据,其中包含应处理的多个项目。数据是一系列json对象。有没有办法将响应转换为这些对象的流,不需要我将整个响应读入内存?
阅读文档时提到"chunked responses",这似乎与我想要的一致。如何在喷涂客户端管道中使用它?
答案 0 :(得分:2)
由于http://boldradius.com/blog-post/VGy_4CcAACcAxg-S/streaming-play-enumerators-through-spray-using-chunked-responses上发现的优秀文章,我今天刚刚实施了类似的内容。
基本上,您要做的是在您的一个Route定义中获取RequestContext,并获取对其“responder”Actor的引用。这是一个Actor,Spray将响应发送回发送原始请求的客户端。
要发回分块响应,您必须发出响应正在开始的信号,然后逐个发送块,然后最终发出响应已完成的信号。您可以通过spray.http包中的ChunkedResponseStart,MessageChunk和ChunkedMessageEnd类来完成此操作。
基本上我最终要做的是将响应发送为一系列这样的类:
0)使用Routes输入的一大堆导入和一个case对象:
import akka.actor.{Actor, ActorRef}
import spray.http._
import akka.actor.ActorRef
import akka.util.Timeout
import akka.pattern.ask
import spray.http.HttpData
import scala.concurrent.duration._
import scala.concurrent.{ExecutionContext, Future}
import akka.actor.{ActorContext, ActorRefFactory, Props}
import spray.http.{HttpData, ContentType}
import spray.routing.RequestContext
import scala.concurrent.ExecutionContext
import scala.concurrent.ExecutionContext.Implicits.global
import spray.json.RootJsonFormat
import spray.http.MediaTypes._
object Messages {
case object Ack
}
1)从你的路线中获取requestContext:
path ("asdf") {
get { requestContext => {
... further code here for sending chunked response ...
}
}
2)启动响应(作为JSON信封,在这种情况下将把响应数据保存在名为“myJsonData”的JSON数组中):
responder.forward(ChunkedResponseStart(HttpResponse(entity = HttpEntity(`application/json`, """{"myJsonData": ["""))).withAck(Ack))
3)迭代你的结果数组,将它们的JSONified版本作为JSON数组中的元素发送到响应中,逗号分隔,直到发送最终元素 - 然后不需要尾随逗号:
requestContext.responder.forward(MessageChunk(HttpData(myArray.toJson).withAck(Ack))
if (!lastElement) { // however you work this out in your code!
requestContext.responder.forward(MessageChunk(HttpData(",").withAck(Ack))
}
4)当没有什么可以发送时,关闭JSON信封:
responder.forward(MessageChunk("]}").withAck(Ack))
并发出响应的结束信号:
responder.forward(ChunkedMessageEnd().withAck(Ack))
在我的解决方案中,我一直在使用Play Iteratees和Enumerators,所以我没有在这里包含大块代码,因为它们与这些可能不适合您需求的机制非常相关。 “withAck”调用的要点是,当网络发出可以接受更多块的信号时,这将导致响应者询问确认消息。理想情况下,您可以制作代码,以便在将来发送更多块之前等待Ack消息的返回。
我希望上面的内容可能会给你一个至少10个起点,正如我所说,这些概念在我链接的文章中得到了很好的解释!
谢谢, 邓肯