Я только что реализовал что-то подобное сегодня, благодаря отличной статье, найденной в http://boldradius.com/blog-post/VGy_4CcAACcAxg-S/streaming-play-enumerators-through-spray-using-chunked-responses.
По существу, вы хотите, чтобы получить RequestContext в одном из определений маршрута и получить ссылку на его «ответчика». Это Актер, с помощью которого Spray отправляет ответы обратно клиенту, который отправил исходный запрос.
Чтобы отправить обратно ответный ответ, вы должны сообщить, что ответ начинается, а затем посылать куски по одному, а затем, наконец, сигнализировать о завершении ответа. Вы делаете это через классы ChunkedResponseStart, MessageChunk и ChunkedMessageEnd из пакета spray.http.
По сути то, что я в конечном итоге делает посылает ответ в виде ряда из этих классов, как это:
0) связкой импорта положить в класс со своими маршрутами в и объекта дела:
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, который будет держать данные ответа в массиве JSON под названием «MyJsonData» в данном случае):
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 и счетчиками и поэтому я не включенными большими кусками кода здесь, потому что они очень тесно связаны с этими механизмами, которые не могут быть пригодны для ваших нужд. Точка вызова «withAck» заключается в том, что это приведет к тому, что ответчик запросит сообщение подтверждения, когда сеть сообщит, что это нормально, чтобы принимать больше кусков. В идеале вы создадите свой код, чтобы дождаться возврата сообщения Ack в будущем, прежде чем отправлять больше кусков.
Надеюсь, что вышеизложенное может дать вам стартер по меньшей мере десять, и, как я уже сказал, эти концепции очень хорошо объясняются в статье, в которой я связан!
Thanks, Duncan