2016-07-08 29 views
5

Buduję mikro-usługę za pomocą Play Framework 2.3.x za pomocą Scala (w obu jestem początkujący), ale nie mogę znaleźć sposobu na przesłanie żądania ciało.Play Scala: Jak przesyłać żądania treściowe

Oto problem:

muszę punkt końcowy /transform gdzie mogę otrzymać ogromny plik TSV że będę analizować i renderowania w innym formacie: Prosty transformacji. Problem polega na tym, że każde polecenie w moim kontrolerze działa "za późno". Czeka na pełny plik przed uruchomieniem kodu.

Przykład:

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

Chcę być w stanie odczytać linię po linii ciała żądanie podczas jej przesyłania i procesu już wniosek bez konieczności oczekiwania na plik, który ma być odbierany całkowicie.

Każda wskazówka byłaby mile widziane.

+0

przeanalizować treść żądania jako wieloczęściowe dane formularza. Może to rozwiązać twój problem. – Abhi

Odpowiedz

8

Ta odpowiedź dotyczy gry w wersji 2.5.x i nowszej, ponieważ korzysta z interfejsu API strumieni Akka, który zastąpił strumieniowanie oparte na Iteratee Play w tej wersji.

Zasadniczo można utworzyć analizator treści, który zwraca wartość Source[T], którą można przekazać do Ok.chunked(...). Jednym ze sposobów na to jest użycie Accumulator.source[T] w analizatorze treści. Na przykład, działanie, które właśnie wrócił dane wysyłane do niego verbatim może wyglądać następująco:

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) 
} 

Jeśli chcesz zrobić coś takiego przekształcenia pliku TSV można użyć Flow przekształcić źródła, np

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") 
} 

Może być więcej inspiracji w sekcji Directing the Body Elsewhere w dokumentach Play.

+0

Dzięki! Doszedłem do wniosku, że to kwestia, która sprawi, że będę pracował nad Play 2.3.x. Ale prawdopodobnie spróbuję tego po prostu dla zabawy na 2.5.x. – Cecile