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