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.

Никогда не выполняйте сложные вычисления внутри фильтров, делайте фильтры максимально легкими.

Другие вопросы по тегам