2012-06-10 31 views
6

我通過覆蓋GlobalSettings的onRouteRequest方法攔截所有對我的應用程序的請求。現在,我需要從這裏發送一些數據到已發送的動作,以便在所有動作中不執行所有這些計算。如何將屬性設置爲傳遞給super onRouteRequest方法的請求(play.api.mvc.RequestHeader)對象?如何在PlayFramework中將變量傳遞給攔截請求中的Action?

+0

設置的屬性不可用,因爲在功能性,我們是在一個不變的環境。因此,例如在會話中添加東西時,您可以使用'withSession'創建一個「新的東西」。並且在onRouteRequest的背景下,您無法創建新的請求,因爲您無法將此新內容添加到您的基礎操作 –

+0

+100,同一條船上,有一個數據片段以注入適用於ALL路線/操作的請求-types。我想在一個地方進行數據計算,onRouteRequest,然後在應用程序中的任何地方隱式請求在範圍內,可以訪問數據(而不是在不同的地方重新計算它,或者爲每個Action添加樣板來處理它)。 – virtualeyes

+0

@andypetrella scala並非純粹的功能。我們可以將數據注入到通過操作組合和WrappedRequest的請求中,從而有效修改請求後路由。我會非常喜歡佔位符Map [String,String]在onRouteRequest中設置。您可以複製請求,例如爲RequestHeader上的「標籤」映射賦值。玩當然,吹走你的寶貴數據,使用標籤地圖路由結果(控制器方法,類型GET等) – virtualeyes

回答

2

您的需求,我使用onRouteRequest將工作(優雅至少)沒有的事。

但是,讓我們嘗試使用一個專用的結構進行攔截。

這裏是你如何能攔截請求,計算一些通用的東西,並把它傳遞給行動

首先,這裏是有一個方法intercept和便利的方法usernameInterceptor對象:

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")) 

} 

正如你可以看到,工人功能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,你就可以測試這個流程做:

  • /託管/假?主機=爲myhost => 404,因爲在第一次爲myhost是不緩存和我提供了虛假的檢查樣機
  • /託管/真的嗎?主機=爲myhost =>不在緩存中,但它會添加它,然後沒有404
  • /託管/ anotherHosted /假?主機=爲myhost =>在緩存中,因爲它託管=>無404
  • /託管/ anotherHosted /假?主機= 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 [email protected](_) => 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) 
    } 
} 
+0

謝謝Andy,讓我告訴你確切的情況下,我正在構建一個託管應用程序,用戶可以註冊並映射其域名。當他們的用戶/客戶碰到他們的映射域時,它首先檢查域是由我們託管還是返回404錯誤。如果該域名是託管的,我想將網站信息傳遞給所有的操作,以便我不在其中再次獲取它。 – Aman