玩2.5.x如何修改响应的内容headers即无缓存?
Play 2.5.x how to modify the content headers of the response i.e. for no cache?
我使用 Scala 和 Play 2.5.10 实现了以下可重用的组合操作,目的是通过更改响应来禁用浏览器中的缓存 headers:
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 plugin 监控网络流量我看到响应 headers 不包含 "no cache" 修改...我做错了什么?
您的代码有问题
问题出在 andThen
。 andThen
丢弃 return 值。所以转换后的 result
和新的 headers 被丢弃了。
删除 andThen
并使其成为 map
。
andThen
用于 运行 在调用它的未来完成后进行副作用计算。
andThen
return的计算是一个与原始 future 具有相同结果的 Future,并丢弃了 andThen
中计算的 return 类型。
这是标准库中 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
}
其他同样的方法
您可以使用播放过滤器 Filter
来更改 headers,也可以用于做一些预处理和 post 处理工作。
您可以通过检查请求的 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 将被设置,而对于其他路由,相同的 headers 将被传播。
注意在 play 应用程序的根文件夹中创建过滤器,如果您没有将过滤器添加到 application.conf
切勿 运行 在过滤器内部进行繁重的 运行 计算,使过滤器尽可能轻便。
我使用 Scala 和 Play 2.5.10 实现了以下可重用的组合操作,目的是通过更改响应来禁用浏览器中的缓存 headers:
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 plugin 监控网络流量我看到响应 headers 不包含 "no cache" 修改...我做错了什么?
您的代码有问题
问题出在 andThen
。 andThen
丢弃 return 值。所以转换后的 result
和新的 headers 被丢弃了。
删除 andThen
并使其成为 map
。
andThen
用于 运行 在调用它的未来完成后进行副作用计算。
andThen
return的计算是一个与原始 future 具有相同结果的 Future,并丢弃了 andThen
中计算的 return 类型。
这是标准库中 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
}
其他同样的方法
您可以使用播放过滤器 Filter
来更改 headers,也可以用于做一些预处理和 post 处理工作。
您可以通过检查请求的 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 将被设置,而对于其他路由,相同的 headers 将被传播。
注意在 play 应用程序的根文件夹中创建过滤器,如果您没有将过滤器添加到 application.conf
切勿 运行 在过滤器内部进行繁重的 运行 计算,使过滤器尽可能轻便。