我通过覆盖 GlobalSettings 的 onRouteRequest 方法来拦截对我的播放应用程序的所有请求。现在,我需要从这里将一些数据发送到发送的操作,这样我就不会在所有操作中执行所有这些计算。如何为传递给超级 onRouteRequest 方法的请求 (play.api.mvc.RequestHeader) 对象设置属性?
问问题
1589 次
1 回答
2
为了您的需要,我不会使用onRouteRequest
will 工作(至少优雅地)。
但是让我们尝试使用专用的结构进行拦截。
以下是您如何拦截请求、计算一些通用内容并将其传递给 Action
首先,这是一个Interceptor
具有方法intercept
和便捷方法的对象username
:
object Interceptor {
def intercept[A, B](f: RequestHeader => Option[B], e: RequestHeader => Result)(action: B => Action[A]): Action[(Action[A], A)] = {
val bodyParser = BodyParser {
request =>
f(request) map {
b =>
val innerAction = action(b)
innerAction.parser(request).mapDone {
body => body.right.map(innerBody => (innerAction, innerBody))
}
} getOrElse {
Done(Left(e(request)), Input.Empty)
}
}
Action(bodyParser) {
request =>
val (innerAction, innerBody) = request.body
innerAction(request.map(_ => innerBody))
}
}
def username[A](check: RequestHeader => Option[String]): ((String) => Action[A]) => Action[(Action[A], A)] = intercept(check, r => Results.Unauthorized("not logged in"))
}
如您所见,worker 函数intercept
使您有机会根据请求内容计算一些东西。哪种类型的计算结果B
可能会失败(Option
),在这种情况下,有一个处理程序来告诉该做什么。
定义了要计算的内容后,您可以定义action
使用接受 aB
并给出. 的函数Action[A]
。
该username
方法只是一个简单的预定义拦截器,可以让我们定义如何检索登录的用户名,仅用于说明。
现在这是我们如何在您的Controller
//index is defined for both GET and POST in routes, but fails on POST
// thanks to the interceptor that checks at first the used method
// the case mustn't be handled in the Action definition
def index = Interceptor.intercept(
/*check the method*/
request => if (request.method == "GET") Some(request.method) else None,
/*not a GET => bad request*/
request => BadRequest(request.method + " not allowed")
) { /*the computation result*/method => Action {
Ok("The method : " + method)
}
}
//this controller retrieve the username in the session and renders it in a OK response
def secured = Interceptor.username(r => r.session.get("username")) { username => Action {
Ok("You're logged in as " + username)
}
}
//this enables you to logged in => store in session
def login(u:String) = Action { request => {
Ok("Logged in as " + u) withSession(("username" -> u))
}
}
现在,如果您有通用计算,则可以创建预配置的拦截器(这里我使用的是案例类,但只需定义一个部分应用的函数interceptor
就足够了)
case class Intercept[B] (f: RequestHeader => Option[B], e: RequestHeader => Result) {
def apply[A](action: B => Action[A]) = Interceptor.intercept[A,B](f, e)(action)
}
val getInterceptor = Intercept[String](
request => if (request.method == "GET") Some(request.method) else None,
request => BadRequest(request.method + " not allowed")
)
def index2 = getInterceptor { method => Action {
Ok("Da method : " + method)
}
}
与评论相关的编辑:
根据您的评论,以下是使用拦截器的方法(请注意,我已经模拟了主机检索和检查)
使用hosted
and anotherHosted
,您将能够测试此工作流程:
- /hosted/false?host=myhost => 404 因为起初 myhost 没有被缓存,我为检查的模型提供了 false
- /hosted/true?host=myhost => 不在缓存中但它会添加它,然后没有 404
- /hosted/anotherHosted/false?host=myhost => 在缓存中,因为它是托管的 => 没有 404
- /hosted/anotherHosted/false?host=notMyhost => 404
这是代码
def getHost(request:RequestHeader) = request.queryString.get("host").get.head
def checkHost(host:String, b: Boolean) = b
val checkHosted = (b: Boolean) => Intercept[String](
request => {
val host = getHost(request)
Cache.getAs[String](host) match {
case x@Some(_) => x
case None => if (checkHost(host, b)) {
Cache.set(host, host)
Some(host)
} else None
}
},
request => NotFound(getHost(request) + "not hosted")
)
def hosted(b:String) = checkHosted(b.toBoolean) {
host => Action {
Ok("this host is ok : " + host)
}
}
def anotherHosted(b:String) = checkHosted(b.toBoolean) {
host => Action {
Ok("this host is ok : " + host)
}
}
于 2012-06-10T12:51:55.137 回答