GlobalSettings の onRouteRequest メソッドをオーバーライドして、プレイ アプリケーションへのすべてのリクエストをインターセプトしています。ここで、すべてのアクションでこれらすべての計算を実行しないように、ここからディスパッチされたアクションにデータを送信する必要があります。スーパーの onRouteRequest メソッドに渡すリクエスト (play.api.mvc.RequestHeader) オブジェクトに属性を設定するにはどうすればよいですか?
1 に答える
onRouteRequest
あなたの必要性のために、私は(少なくとも優雅に)動作することを気にしません。
しかし、傍受するために専用の構造を使用してみましょう。
リクエストをインターセプトし、一般的なものを計算して 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
を取り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)
}
}
コメントに関連する編集:
あなたのコメントに応じて、インターセプターを使用して行う方法は次のとおりです(ホストの取得とチェックをモックアップしたことに注意してください)
とを使用するhosted
と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)
}
}