3

我正在尝试使用 Play Framework 2.2 构建多租户应用程序,但遇到了问题。我想在全局onRouteRequest(或onRequestJava)中设置一个会话密钥,用于标识用户请求的域的站点 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 中的解决方案示例持开放态度。

4

1 回答 1

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 的源代码以查看如何在过滤器中向会话添加内容的示例。

于 2013-10-07T22:52:56.437 回答