3

我认为这在 Play 1.x 中曾经是可能的,但我在 Play 2.x 中找不到如何做到这一点

我知道 Play 是异步的并且使用Iteratees. 但是,通常对 s 有更好的支持InputStream

(在这种情况下,我将使用像 Jackson 这样的流式 JSON 解析器来处理请求正文。)

如何InputStream从分块的请求正文中获取?

4

2 回答 2

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)
  }
}
于 2014-10-02T12:57:22.123 回答
1

Play 2 是完全异步的,所以这不太可能或不可取。问题InputStream在于没有推回,阅读器InputStream无法与输入进行通信,即它需要更多数据而不阻塞read。从技术上讲,可以编写一个Iteratee可以读取数据并将其放入, 并在请求更多数据之前InputStream等待对readon 的调用,但这会很危险。您必须确保已正确关闭,否则将永远等待(或直到超时),并且必须从与运行不同的线程进行调用,并且或应用程序可能死锁.InputStreamEnumeratorInputStreamEnumeratorreadExecutionContextEnumeratorIteratee

于 2014-07-27T14:21:12.167 回答