Play 2 - Set header on all responses?

2019-02-16 06:35发布

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.

4条回答
劳资没心,怎么记你
2楼-- · 2019-02-16 06:51

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"
    ))
  }
}
查看更多
Melony?
3楼-- · 2019-02-16 06:53

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!")
}
查看更多
放我归山
4楼-- · 2019-02-16 06:55

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.

查看更多
地球回转人心会变
5楼-- · 2019-02-16 07:01

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.

查看更多
登录 后发表回答