如何在Play Framework中验证查询字符串参数

时间:2014-07-01 09:11:19

标签: scala playframework playframework-2.3

我想知道,如何在PlayFramework 2.x中验证查询字符串参数。 假设我有相当常见的移位,限制(DROP,LIMIT)参数的序列,我有 像这样的路线:

# http://example.com/users?shift=0&limit=20 - take first 20 users
GET    /users         Users.list(shift: Int ?= 0, limit: Int ?= 20)

我想保持我的移位并限制我的正确范围,例如从1到60的限制,如果用户试图设置限制如23979,则应该减少到60。 过滤器对此不起作用,导致它们在路由器之后触发。

3 个答案:

答案 0 :(得分:1)

我喜欢biesor的评论,您可以在行动开始时进行验证。如果那是不可能的,那么kfer38的答案也是有效的。我想抛出另一个答案,那就是使用Global对象。 http://www.playframework.com/documentation/2.3.x/ScalaGlobal

全局对象相对于重定向的优势在于它可以立即完成,并且重新配置路由器,而不是重定向,这会为您的运行时间增加毫秒数。由于在路由器接触它们之前做事似乎是一个问题,我提供这个解决方案。

这样的事情会起作用:

object Global extends GlobalSettings {
  override def onRouteRequest(request: RequestHeader): Option[Handler] = {
    // string matching here to get the values
    // rewrite values to what you want
    super.onRouteRequest(request.copy(path = newPath))
  }
}

我用它来删除" /"例如,在路线的末端,而不是重定向,这是非常低效的。我也是这样做的,以避免为了匹配结尾" /"而必须写两倍的路线。

答案 1 :(得分:0)

您可以检查控制器Users.list(shift: Int, limit: Int)中的约束。然后,您可以使用自定义值重定向,而不是抛出异常。防爆。 if (limit > 60) Redirect(routes.controllers.Users.list(shift, 60))

答案 2 :(得分:0)

Michael's方法适用于此,但也有一些有趣的事情。 如果我过滤覆盖onRouteRequest的查询参数,它会过滤传递给动作函数的参数,但不会过滤请求对象中的查询字符串参数:

def users(shift: Int, limit: Int) = Action { req =>
  Logger.debug("shift: " + shift)
  Logger.debug("shiftQS: " + req.getQueryString("shift"))

如果我们要求/users?shift=-2我们的班次将被过滤,而shiftQS则不会!但是如果仅使用Filter,情况似乎会有所不同,它可以过滤查询字符串参数但不能过滤您的参数。因此,要过滤查询字符串,您还应添加Play Filter。我的最终实现包含这样的内容:

// Write your filter and mix it to Global
object SeqFilter extends EssentialFilter {
  def apply(next: EssentialAction): EssentialAction = new EssentialAction {
    def apply(req: RequestHeader): Iteratee[Array[Byte], SimpleResult] = {
      next(doFilter(req))
    }
  }

  def doFilter(req: RequestHeader): RequestHeader = {
    if (/* queryString contains invalid parameters */) {
      val qs = /* You filtered queryString */
      req.copy(queryString = qs)
    } else {
      req
    }
  }
}

// Alson use your filter in onRouteRequest in Global object
override def onRouteRequest(req: RequestHeader): Option[Handler] = {
  super.onRouteRequest(SeqFilter.doFilter(req))
}