简体   繁体   English

使用Spray Route传输动态内容

[英]Streaming dynamic content, with Spray Route

I am developing a web service that serves some relatively large files, each created dynamically at request time. 我正在开发一个Web服务,该服务提供一些相对较大的文件,每个文件都在请求时动态创建。 In my case this is a ZIP archive file that contains a bunch of files, but I assume the same problem will occur with other types of dynamically created files. 在我的情况下,这是一个包含一堆文件的ZIP存档文件,但是我假设其他类型的动态创建文件也会出现相同的问题。

The problem is that I would like to avoid creating the ZIP file on disk, but rather just stream it directly to the HTTP response. 问题是我想避免在磁盘上创建ZIP文件,而只是将其直接流式传输到HTTP响应。 One way I thought about is to use chunked streaming, which means that a streaming actor sends a chunk at the time, and "waits" for acknowledgment from the responder before sending the next chunks. 我考虑过的一种方法是使用分块式流传输,这意味着流式传输器参与者当时发送一个块,并在发送下一个块之前“等待”来自响应者的确认。 (see the example of sendStreamingResponse in https://github.com/spray/spray/blob/release/1.1/examples/spray-routing/on-spray-can/src/main/scala/spray/examples/DemoService.scala ) (请参阅https://github.com/spray/spray/blob/release/1.1/examples/spray-routing/on-spray-can/src/main/scala/spray/examples/DemoService.scala中sendStreamingResponse示例)

Unfortunately all the examples I could find show how to do it when your stream is pre-defined, but I'm not quite sure what's the best way to approach this when the stream of data is being prepared in some other future. 不幸的是,我能找到的所有示例都显示了在预定义流时如何执行此操作,但是我不确定在将来准备数据流时,哪种最佳方法是最好的。

In my case, there's a Future started by the HTTP request that does all the heavy work of fetching the files, and writing them into a java.util.zip.ZipOutputStream . 在我的情况下,有一个由HTTP请求启动的Future ,它完成了所有繁重的工作,以提取文件并将它们写入java.util.zip.ZipOutputStream But the way streaming works in Spray is the opposite, because the streaming actor needs to pull the data when it is ready - I can't just push all the data to the stream. 但是,Spray中流式传输的工作方式却相反,因为流式演员需要在准备就绪时提取数据-我不能只是将所有数据推送到流中。

Is this a familiar use case, and what's the best way to tackle it? 这是一个熟悉的用例,解决它的最佳方法是什么?

I think we can use Spray's builtin marshaller if we produce a Steam[Byte] . 我认为,如果我们生成Steam[Byte]则可以使用Spray的内置编组器。 I haven't tried it but something like this should work (I've done something similar in the past with dynamic image resizing and serving large files). 我还没有尝试过,但是类似的东西应该可以工作(过去我通过动态图像调整大小和提供大文件来做类似的事情)。

val pipeIn = new PipedInputStream()
val pipeOut = new PipedOutputStream(pipeIn)
val out = new ByteArrayOutputStream()
val st = new ZipOutputStream(out)
Future{
  writeToZip(st)
  out.writeTo(pipeOut)
}
val streamResponse: Stream[Byte] = Stream.continually(pipeIn.read).takeWhile(_ != -1).map(_.toByte)
complete(streamResponse)

Spray's stream marshaller will automatically produce a chunked response. Spray的流编组器将自动产生分块响应。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM