代码之家  ›  专栏  ›  技术社区  ›  SkyWalker

Play 2.5.x如何修改响应的内容头,即无缓存?

  •  0
  • SkyWalker  · 技术社区  · 8 年前

    使用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 plugin 为了监控网络流量,我看到响应头不包含“无缓存”修改……我做错了什么?

    1 回复  |  直到 8 年前
        1
  •  1
  •   Nagarjuna Pamu    8 年前

    你的代码有问题吗

    问题在于 andThen . 然后 丢弃返回值。因此,改变了 result 新的标题将被丢弃。

    去除 然后 让它成为 map .

    然后 用于在调用它的未来完成后立即运行副作用计算。

    计算 然后 返回结果与原始Future相同的Future,并丢弃内部计算的返回类型 然后 .

    以下是 然后 来自标准库。

     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 更改标题,也可以用于执行一些预处理和后处理工作。

    通过检查请求的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,并且对于其他路由,将传播相同的报头。

    注意:在play应用程序的根文件夹中创建过滤器。如果没有,则必须将过滤器添加到application.conf

    不要在过滤器内运行繁重的计算,使过滤器尽可能轻。