I'm aware from Setting HTTP headers in Play 2.0 (scala)? that you can set response headers on a case-by-case basis by doing, for example, Ok("hello").withHeaders(PRAGMA -> "no-cache")
.
What if you want to set that header, or a few different headers, on responses from all your Actions? You wouldn't want to repeat the withHeaders
everywhere. And since this is more like an application-wide configuration, you might not want Action writers to have to use a different syntax to get your headers (e.g. OkWithHeaders(...)
)
What I have now is a base Controller class that looks like
class ContextController extends Controller {
...
def Ok(h: Html) = Results.Ok(h).withHeaders(PRAGMA -> "no-cache")
}
but that doesn't feel quite right. It feels like there should be more of an AOP-style way of defining the default headers and having them added to each response.
In your Global.scala
, wrap every call in an action:
import play.api._
import play.api.mvc._
import play.api.Play.current
import play.api.http.HeaderNames._
object Global extends GlobalSettings {
def NoCache[A](action: Action[A]): Action[A] = Action(action.parser) { request =>
action(request) match {
case s: SimpleResult[_] => s.withHeaders(PRAGMA -> "no-cache")
case result => result
}
}
override def onRouteRequest(request: RequestHeader): Option[Handler] = {
if (Play.isDev) {
super.onRouteRequest(request).map {
case action: Action[_] => NoCache(action)
case other => other
}
} else {
super.onRouteRequest(request)
}
}
}
In this case, I only call the action in dev mode, which makes most sense for a no-cache instruction.
The topic is quite old now, but with Play 2.1 it is even simpler now.
Your Global.scala
class should look like this :
import play.api._
import play.api.mvc._
import play.api.http.HeaderNames._
/**
* Global application settings.
*/
object Global extends GlobalSettings {
/**
* Global action composition.
*/
override def doFilter(action: EssentialAction): EssentialAction = EssentialAction { request =>
action.apply(request).map(_.withHeaders(
PRAGMA -> "no-cache"
))
}
}
The easiest way to achieve fine-grained control is in using wrapped actions. In your case it can be something like that:
object HeaderWriter {
def apply(f: Request[AnyContent] => SimpleResult):Action[AnyContent] = {
Action { request =>
f(request).withHeaders(PRAGMA -> "no-cache")
}
}
}
and use it in such manner:
def doAction = HeaderWriter { request =>
... do any stuff your want ...
Ok("Thats it!")
}
There are too ways. You can use action-composition. Then you must declare at every Controller that you want set here the header. Another option is to use the GlobalSettings.
There are similar solutions for java, too.