1

我正在使用 Spray 查询 REST 端点,该端点将返回大量数据,其中包含应处理的多个项目。数据是一系列 json 对象。有没有办法将响应转换为这些对象的流,而不需要我将整个响应读入内存?

阅读文档时提到了“分块响应”,这似乎与我想要的一致。如何在喷雾客户端管道中使用它?

4

1 回答 1

2

我今天刚刚实现了类似的东西,这要感谢http://boldradius.com/blog-post/VGy_4CcAACcAxg-S/streaming-play-enumerators-through-spray-using-chunked-responses上的优秀文章。

本质上,您要做的是在您的一个 Route 定义中获取 RequestContext,并获取对其“响应者”Actor 的引用。这是 Spray 将响应发送回发送原始请求的客户端的 Actor。

要发回分块响应,您必须发出响应开始的信号,然后逐个发送块,最后发出响应已完成的信号。您可以通过 spray.http 包中的 ChunkedResponseStart、MessageChunk 和 ChunkedMessageEnd 类执行此操作。

基本上我最终做的是将响应作为一系列这样的类发送:

0) 将一堆导入放入包含您的 Routes 的类中,以及一个案例对象:

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) 遍历您的结果数组,将它们的 JSON 化版本作为 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 消息,然后再发送更多块。

我希望以上内容至少可以为您提供十个入门,正如我所说,这些概念在我链接到的文章中得到了很好的解释!

谢谢,邓肯

于 2015-09-14T20:57:37.983 回答