我认为在Play 1.x中曾经有过这种情况,但我无法在Play 2.x中找到如何做到这一点
我知道Play是异步的并使用Iteratee
s。但是,对InputStream
的支持通常会有更好的支持。
(在这种情况下,我将使用像Jackson这样的流式JSON解析器来处理请求体。)
如何从分块的请求正文中获取InputStream
?
答案 0 :(得分:2)
我能够使用以下代码实现此目的:
// 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)
}
}
答案 1 :(得分:0)
Play 2意味着完全异步,因此这不容易或不可取。 InputStream
的问题是没有回退,InputStream
的读者无法与输入进行通信,表明它需要更多数据而不会阻塞read
。从技术上讲,可以编写一个可以读取数据并将其放入Iteratee
的{{1}},并在询问{InputStream
之前等待read
上的InputStream
来电。 {1}}获取更多数据,但这会很危险。您必须确保Enumerator
已正确关闭,或InputStream
将永远等待(或直到超时),并且必须从线程调用Enumerator
与read
和ExecutionContext
不在同一Enumerator
上运行,或者应用程序可能会死锁。