玩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" 修改...我做错了什么?

您的代码有问题

问题出在 andThenandThen 丢弃 return 值。所以转换后的 result 和新的 headers 被丢弃了。

删除 andThen 并使其成为 map

andThen 用于 运行 在调用它的未来完成后进行副作用计算。

andThenreturn的计算是一个与原始 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

切勿 运行 在过滤器内部进行繁重的 运行 计算,使过滤器尽可能轻便。