如何在Play中从请求中获取InputStream

时间:2014-07-26 14:45:02

标签: scala playframework-2.0 chunked

我认为在Play 1.x中曾经有过这种情况,但我无法在Play 2.x中找到如何做到这一点

我知道Play是异步的并使用Iteratee s。但是,对InputStream的支持通常会有更好的支持。

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

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

2 个答案:

答案 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将永远等待(或直到超时),并且必须从线程调用EnumeratorreadExecutionContext不在同一Enumerator上运行,或者应用程序可能会死锁。