【问题标题】:How to get InputStream from request in Play如何从 Play 中的请求中获取 InputStream
【发布时间】:2014-07-26 14:45:02
【问题描述】:
我认为这在 Play 1.x 中曾经是可能的,但我在 Play 2.x 中找不到如何做到这一点
我知道 Play 是异步的并且使用 Iteratees。但是,通常对InputStreams 有更好的支持。
(在这种情况下,我将使用像 Jackson 这样的流式 JSON 解析器来处理请求正文。)
如何从分块的请求正文中获取InputStream?
【问题讨论】:
标签:
scala
playframework-2.0
chunked
【解决方案1】:
我能够使用以下代码来实现这一点:
// I think all of the parens and braces line up -- copied/pasted from code
val pos = new PipedOutputStream()
val pis = new PipedInputStream(pos)
val result = Promise[Either[Errors, String]]()
def outputStreamBodyParser = {
BodyParser("outputStream") {
requestHeader =>
val length = requestHeader.headers(HeaderNames.CONTENT_LENGTH).toLong
Future {
result.completeWith(saveFile(pis, length)) // save returns Future[Either[Errors, String]]
}
Iteratee.fold[Array[Byte], OutputStream](pos) {
(os, data) =>
os.write(data)
os
}.map {
os =>
os.close()
Right(os)
}
}
}
Action.async(parse.when(
requestHeaders => {
val maybeContentLength = requestHeaders.headers.get(HeaderNames.CONTENT_LENGTH)
maybeContentLength.isDefined && allCatch.opt(maybeContentLength.get.toLong).isDefined
},
outputStreamBodyParser,
requestHeaders => Future.successful(BadRequest("Missing content-length header")))) {
request =>
result.future.map {
case Right(fileRef) => Ok(fileRef)
case Left(errors) => BadRequest(errors)
}
}
【解决方案2】:
Play 2 旨在完全异步,因此这不太可能或不可取。 InputStream 的问题是没有推回,InputStream 的读者无法在不阻塞read 的情况下与输入进行通信,它需要更多数据。从技术上讲,可以编写一个可以读取数据并将其放入InputStream 的Iteratee,并在向Enumerator 询问更多数据之前等待InputStream 上对read 的调用,但它会很危险。您必须确保 InputStream 已正确关闭,否则 Enumerator 将永远等待(或直到超时),并且必须从不在ExecutionContext 与 Enumerator 和 Iteratee 相同,否则应用程序可能会死锁。