6

GlobalSettings の onRouteRequest メソッドをオーバーライドして、プレイ アプリケーションへのすべてのリクエストをインターセプトしています。ここで、すべてのアクションでこれらすべての計算を実行しないように、ここからディスパッチされたアクションにデータを送信する必要があります。スーパーの onRouteRequest メソッドに渡すリクエスト (play.api.mvc.RequestHeader) オブジェクトに属性を設定するにはどうすればよいですか?

4

1 に答える 1

2

onRouteRequestあなたの必要性のために、私は(少なくとも優雅に)動作することを気にしません。

しかし、傍受するために専用の構造を使用してみましょう。

リクエストをインターセプトし、一般的なものを計算して Action に渡す方法は次のとおりです。

まず、メソッドと便利なInterceptorメソッドを持つオブジェクトを次に示します。interceptusername

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を取りBを与える関数を使用して定義できます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)
    }
  }

コメントに関連する編集:

あなたのコメントに応じて、インターセプターを使用して行う方法は次のとおりです(ホストの取得とチェックをモックアップしたことに注意してください)

とを使用するhostedanotherHosted、このワークフローをテストできます。

  • /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 に答える