Play Framework Scala:如何流式处理请求正文 [英] Play Framework Scala: How to Stream Request Body

查看:115
本文介绍了Play Framework Scala:如何流式处理请求正文的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用Scala使用Play Framework 2.3.x构建微服务(我都是这两者的初学者),但是我想不出一种方法来流式处理我的请求正文.

I'm building a micro-service using Play Framework 2.3.x using Scala (I'm a beginner in both) but I can't figure out a way to stream my request body.

问题出在这里

我需要一个端点/transform,在这里我可以接收一个巨大的TSV文件,该文件将以另一种格式进行解析和呈现:简单转换.问题是控制器中的每个命令都太迟了".启动代码之前,它将等待接收完整的文件.

I need an endpoint /transform where I can receive a huge TSV file that I will parse and render in another format: simple transformation. The problem is that every single command in my controller is ran "too late". It waits to receive the full file before starting the code.

示例:

  def transform = Action.async {
    Future {
      Logger.info("Too late")
      Ok("A response")
    }
  }

我希望能够在上传过程中逐行读取请求正文并已经处理了请求,而不必等待文件被完全接收.

I want to be able to read line-by-line the request body during its upload and process already the request without having to wait for the file to be received completely.

任何提示都会受到欢迎.

Any hint would be welcome.

推荐答案

此答案适用于Play 2.5.x及更高版本,因为它使用Akka流API取代了该版本中基于Play Iteratee的流.

This answer applies to Play 2.5.x and higher since it uses the Akka streams API that replaced Play's Iteratee-based streaming in that version.

基本上,您可以创建一个返回Source[T]的正文解析器,然后将其传递给Ok.chunked(...).一种方法是在主体解析器中使用Accumulator.source[T].例如,一个刚刚返回原样发送数据的动作可能看起来像这样:

Basically, you can create a body parser that returns a Source[T] that you can pass to Ok.chunked(...). One way to do this is to use Accumulator.source[T] in the body parser. For example, an action that just returned data sent to it verbatim might look like this:

def verbatimBodyParser: BodyParser[Source[ByteString, _]] = BodyParser { _ =>
  // Return the source directly. We need to return
  // an Accumulator[Either[Result, T]], so if we were
  // handling any errors we could map to something like
  // a Left(BadRequest("error")). Since we're not
  // we just wrap the source in a Right(...)
  Accumulator.source[ByteString]
    .map(Right.apply)
}

def stream = Action(verbatimBodyParser) { implicit request =>
  Ok.chunked(request.body)
}

如果要执行诸如转换TSV文件的操作,则可以使用Flow来转换源,例如:

If you want to do something like transform a TSV file you can use a Flow to transform the source, e.g:

val tsvToCsv: BodyParser[Source[ByteString, _]] = BodyParser { req =>

  val transformFlow: Flow[ByteString, ByteString, NotUsed] = Flow[ByteString]
    // Chunk incoming bytes by newlines, truncating them if the lines
    // are longer than 1000 bytes...
    .via(Framing.delimiter(ByteString("\n"), 1000, allowTruncation = true))
    // Replace tabs by commas. This is just a silly example and
    // you could obviously do something more clever here...
    .map(s => ByteString(s.utf8String.split('\t').mkString(",") + "\n"))

  Accumulator.source[ByteString]
    .map(_.via(transformFlow))
    .map(Right.apply)
}

def convert = Action(tsvToCsv) { implicit request =>
  Ok.chunked(request.body).as("text/csv")
}

指导身体可能会带来更多启发Play文档的其他地方部分.

这篇关于Play Framework Scala:如何流式处理请求正文的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆