1

Я режу зубы на Play, используя книгу Reactive Web Applications: Covers Play, Akka, and Reactive Streams. Глава 4, помимо прочего, учит писать фильтр, но код, показанный в книге, не компилируется, потому что в Play 2.4.x Result.body используется как Enumerator[Array[Byte]], а в 2.5.x это play.api.http.HttpEntity.Play Framework: Как изменить тело ответа без блокировки?

Моя версия фильтра, как показано ниже:

class ScoreFilter @Inject()(implicit val mat: Materializer, ec: ExecutionContext) extends Filter { 
    override def apply(nextFilter: (RequestHeader) => Future[Result])(rh: RequestHeader) = 
    nextFilter(rh).map { result => 
     if (result.header.status == OK || result.header.status == NOT_ACCEPTABLE) { 
     val correct = result.session(rh).get("correct").getOrElse(0) 
     val wrong = result.session(rh).get("wrong").getOrElse(0) 

     val score = s"\nYour current score is: $correct correct " + 
      s"answers and $wrong wrong answers" 

     val contentType = result.body.contentType 
     val scoreByteString = ByteString(score.getBytes(UTF_8)) 
     val maybeNewBody = result.body.consumeData.map(_.concat(scoreByteString)) 

     import scala.concurrent.duration._ 
     val newBody = Await.result(maybeNewBody, 10 seconds) 

     result.copy(body = Strict(newBody, contentType)) 
     } else { 
     result 
     } 
    } 
} 

В книге:

// result.body returns a play.api.http.HttpEntity which doesn't have an andThen method 
val newBody = result.body andThen Enumerator(score.getBytes(UTF_8)) 
result.copy(body = newBody) 

Как вы можете видеть, моя версия фильтра работает, но он блокирует на будущее. Мне интересно, есть ли лучший способ сделать это без блокировки?

P.S .: Прежде чем уволить мой вопрос как дубликат, имейте в виду, что я прочитал все следующие потоки, и они преобразуют тело ответа в строку, чего я не хочу.

Scala play http filters: how to find the request body

Play framework filter that modifies json request and response

Play 2.4: intercept and modify response body

ответ

2

, если вы хотите, чтобы избежать Await.result, вы можете сделать:

nextFilter(rh).flatMap { result => 
    ... 
    maybeNewBody map { newBody => 
    result.copy(body = Strict(newBody, contentType)) 
    } 
} else Future.successful(result) 

(обратите внимание на изменение map к flatMap)

+0

Это работает, но мне нужно изменить тело на «Строгий». Мне любопытно, можно ли этого избежать, используя 'Iteratees' и' Enumerators'? –

+0

Единственными опциями для 'HttpEntity' являются' Strict', 'Streamed' и' Chunked'. согласно документации, 'Strict' - это то, что вы хотите здесь, так как у вас есть содержимое в памяти: https://playframework.com/documentation/2.5.2/api/java/play/http/HttpEntity.html – handler

+0

Вот что я Однако я думал, что в фильтре мы всегда будем знать тип тела. Как вы сказали, есть 3. Я послал по электронной почте автора Мануэля Бернхардта. Будет опубликован здесь, если он предоставит альтернативу. Тем временем я приму свой ответ. –

Смежные вопросы