Play 2.5.x как изменить заголовки содержимого ответа, т.е. без кеша?
Используя Scala и Play 2.5.10, я реализовал следующее многократно используемое действие для композиции и с целью отключения кэширования в браузере путем изменения заголовков ответов:
import play.api.http.HeaderNames
import play.api.mvc._
import scala.concurrent.Future
import scala.util.{Failure, Success}
import scala.concurrent.ExecutionContext.Implicits.global
case class NoCache[A](action: Action[A]) extends Action[A] with HeaderNames {
def apply(request: Request[A]): Future[Result] = {
action(request).andThen {
case Success(result) => result.withHeaders(
(CACHE_CONTROL -> "no-cache, no-store, must-revalidate"),
(PRAGMA -> "no-cache"),
(EXPIRES -> "0")
)
case Failure(result) => result
}
}
lazy val parser = action.parser
}
Затем я снова использую его в моей реализации действий контроллера, как это:
def link = NoCache {
deadbolt.SubjectPresent()() { implicit request =>
Future {
Ok(views.html.account.link(userService, auth))
}
}
}
Я остановился на NoCache
реализации, и он выполняется правильно, однако, с помощью плагина Web Developer Firefox для мониторинга сетевого трафика, я вижу, что заголовки ответа не содержат изменений "без кэша"... что я делаю неправильно?
1 ответ
Проблема с вашим кодом
Проблема с andThen
, andThen
отбрасывает возвращаемое значение. Итак, преображенный result
с новыми заголовками отбрасывается.
Удалить andThen
и сделать это map
,
andThen
используется для запуска вычисления побочных эффектов сразу после завершения будущего, в котором оно вызывается.
Расчет andThen
возвращает Future с тем же результатом, что и исходное будущее, и отбрасывает возвращаемый тип вычисления внутри andThen
,
Вот реализация andThen
из стандартной библиотеки.
def andThen[U](pf: PartialFunction[Try[T], U])(implicit executor: ExecutionContext): Future[T] = {
val p = Promise[T]()
onComplete {
case r => try pf.applyOrElse[Try[T], Any](r, Predef.conforms[Try[T]]) finally p complete r
}
p.future
}
Исправление вашего кода
case class NoCache[A](action: Action[A]) extends Action[A] with HeaderNames {
def apply(request: Request[A]): Future[Result] = {
action(request).map { result =>
result.withHeaders(
(CACHE_CONTROL -> "no-cache, no-store, must-revalidate"),
(PRAGMA -> "no-cache"),
(EXPIRES -> "0")
)
}
}
lazy val parser = action.parser
}
Другой способ сделать то же самое
Вы можете использовать фильтры Play Filter
изменить заголовки, а также может быть использован для выполнения некоторой предварительной обработки и последующей обработки.
Вы можете указать только определенные маршруты, проверив URI запроса.
import akka.stream.Materializer
import com.google.inject.{Inject, Singleton}
import play.api.http.DefaultHttpFilters
import play.api.mvc.{Filter, RequestHeader, Result}
import play.mvc.Http.HeaderNames
import scala.concurrent.Future
@Singleton
class Filters @Inject() (fooFilter: FooFilter) extends DefaultHttpFilters(fooFilter) {}
@Singleton
class FooFilter @Inject() (implicit override val mat: Materializer) extends Filter {
override def apply(f: (RequestHeader) => Future[Result])(rh: RequestHeader): Future[Result] = {
f(rh).map { result =>
if (rh.uri.startsWith("/foo"))
result.withHeaders(HeaderNames.CACHE_CONTROL -> "no-cache")
else result
}
}
}
В приведенном выше примере для /foo
Маршрут cache_control будет установлен, и для других маршрутов будут распространяться те же заголовки.
Примечание. Создайте фильтры в корневой папке приложения воспроизведения, если нет необходимости добавлять фильтры в application.conf.
Никогда не выполняйте сложные вычисления внутри фильтров, делайте фильтры максимально легкими.