2012-06-10 8 views
6

Przechwytuję wszystkie żądania do mojej aplikacji odtwarzania, zastępując metodę GlobalSettings onRouteRequest. Teraz muszę wysłać dane do wysłanej akcji, aby nie wykonywać tych wszystkich obliczeń we wszystkich działaniach. Jak ustawić atrybut dla obiektu request (play.api.mvc.RequestHeader), który przekazuję do metody super onRouteRequest?Jak przekazać zmienną do działania z przechwyconego żądania w PlayFramework?

+0

Ustawienie atrybutu nie jest dostępna, ponieważ w funkcjonalny, jesteśmy w niezmiennej środowiska. Tak więc, na przykład dodając rzeczy do sesji, tworzysz "nowy" z 'withSession'. A w kontekście onRouteRequest nie można utworzyć nowego żądania, ponieważ nie będzie możliwe przekazanie tego nowego do podstawowej akcji –

+0

+100, ta sama łódź, aby fragment danych został wstawiony do Żądania, które dotyczy WSZYSTKICH tras/akcji -types. Chciałbym wykonać obliczenia danych w jednym miejscu, onRouteRequest, a następnie w dowolnym miejscu aplikacji, w której niejawne żądanie jest w zakresie, mieć dostęp do danych (w odróżnieniu od ponownego obliczania w różnych miejscach lub dodawanie tablicy dla każdego działania, aby sobie z tym poradzić). – virtualeyes

+0

@ andypetrella scala nie jest czysto funkcjonalna. Możemy wstrzykiwać dane do kompozycji Request via Action i WrappedRequest, skutecznie modyfikując zapytanie po trasie. Chciałbym bardzo miło zapełnić mapę zastępczą [String, String], aby ustawić w onRouteRequest. Możesz skopiować żądanie i, na przykład, podać wartość do "znaczników" Map na RequestHeader. Zagraj oczywiście, zdmuchnij swoje cenne dane, używając znaczników Mapa dla wyników trasowania (metoda kontrolera, typ GET, itp.) – virtualeyes

Odpowiedz

2

Dla twoich potrzeb nie będę używał funkcji onRouteRequest (przynajmniej elegancko).

Ale spróbujmy użyć specjalnej struktury do przechwycenia.

Oto w jaki sposób można przechwycić żądania, oblicz rodzajowe rzeczy i przekazać go do działania

Przede wszystkim tutaj jest Interceptor obiekt, który ma metodę intercept i wygodny sposób 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")) 

} 

Jak widać, funkcja pracownika intercept daje możliwość obliczenia niektórych rzeczy na podstawie treści żądania. Który wynik obliczeń typu B może się nie udać (Option), w takim przypadku przewodnik będzie mógł powiedzieć, co zrobić.

uwzględniając określić co do obliczenia, można zdefiniować action stosując funkcję, która pobiera B i daje Action[A].

Metoda jest tylko prostym predefiniowanym przechwytywaczem, który umożliwia nam zdefiniowanie sposobu pobierania zalogowanej nazwy użytkownika, aby zilustrować.

Teraz tutaj jest to, jak możemy korzystać zarówno z nich w swojej 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)) 
    } 
    } 

Teraz, jeśli masz ogólne obliczenia można utworzyć wstępnie skonfigurowaną przechwytujących (tu używam klasę przypadku, ale po prostu wyznaczającą funkcja, która częściowo stosuje interceptor wystarczy)

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

EDIT związane z komentarzem:

Odpowiednio do Twojego komentarza, oto jak można to zrobić za pomocą przechwytywania (zauważ, że mam wyśmiewali się na pobieranie hosta i sprawdzania)

Korzystanie hosted i anotherHosted, będziesz mógł przetestować ten obieg:

/gospodarzem /? gospodarz fałszywe
  • = myhost => 404, ponieważ na pierwszy myhost nie są buforowane i pod warunkiem fałszywe sprawdzanego makieta
  • /gospodarzem/host prawda? = myhost => nie w pamięci podręcznej, ale to będzie dodaj, a następnie nie 404
  • /hosted/anotherHosted/false? host = myhost => w pamięci podręcznej, ponieważ jest hostowany => nie 404
  • /hosted/anotherHosted/false?host = notMyhost => 404

Oto kod

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

Dzięki Andy, Pozwól, że ci powiem dokładny scenariusz, buduję hostowaną aplikację, do której użytkownicy mogą się zarejestrować i mapować swoją domenę. Kiedy ich użytkownicy/klienci trafiają na zmapowaną domenę, najpierw sprawdza, czy domena jest hostowana przez nas, czy też zwraca błąd 404. Jeśli domena jest hostowana, chcę przekazać informacje o witrynie wszystkim działaniom, aby nie pobierać jej ponownie. – Aman

Powiązane problemy