我正在尝试使用Play Framework 2.2构建多租户应用程序并遇到了问题。我想在全局onRouteRequest
(或Java中的onRequest
)中设置一个会话密钥,用于标识用户请求的域的站点ID。在几十个其他框架中,这种类型的东西是无痛的(例如Django),但我知道Play中的会话对象显然是不可变的。
所以,现在,我有这样的事情:
override def onRouteRequest(request: RequestHeader): Option[Handler] = {
if (request.session.get("site").isEmpty){
val id = models.Site.getSiteUIDFromURL(request.host.toLowerCase()).toString()
if (!id.isEmpty){
//what goes here to set the session?
}else{
//not found - redirect to a general notFound page
}
}
super.onRouteRequest(request)
}
而且,虽然它不是使用数据库查找的最有效方式,但它现在可用于测试。我需要能够在全局设置会话密钥,但我完全不知道如何做到这一点。如果有更好的方法,我全都耳朵(可能包裹我的控制器?)。
我对Java或Scala中的解决方案示例持开放态度。
答案 0 :(得分:7)
将Play中的操作视为函数调用,输入是请求,输出是结果。如果要更改包装函数调用的结果,则必须先调用该函数,然后应用更改。向会话添加密钥会更改结果,因为会话将在会话cookie中发送到客户端。在上面的代码中,您在尝试更改结果之前尝试进行更改,即在调用super.onRouteRequest
之前。
如果您根本不需要修改路由,请不要在onRouteRequest
中执行此操作,在过滤器中执行此操作,更容易。但假设您确实需要修改路由,那么您需要将过滤器应用于返回的处理程序。这就是它的样子:
override def onRouteRequest(request: RequestHeader): Option[Handler] = {
val maybeSite: Option[String] = request.session.get("site").orElse {
// Let's just assume that getSiteUIDFromUrl returns Option[String], always use Option if you're returning values that might not exist.
models.Site.getSiteUIDFromURL(request.host.toLowerCase())
}
maybeSite.flatMap { site =>
super.onRouteRequest(request).map {
case e: EssentialAction => EssentialAction { req =>
e(req).map(_.withSession("site" -> site))
}
case other => other
}
}
}
检查CSRFFilter的源代码,以查看如何在过滤器中向会话添加内容的示例。