2012-06-10 2 views
6

Ich halte alle Anfragen an meine Play-Anwendung ab, indem ich die onRouteRequest-Methode von GlobalSettings überschreibe. Jetzt muss ich von hier aus Daten an die gesendete Aktion senden, damit ich nicht all diese Berechnungen in allen Aktionen ausführen kann. Wie setze ich ein Attribut auf das Anfrageobjekt (play.api.mvc.RequestHeader), das ich an die super onRouteRequest-Methode übergebe?Wie wird eine Variable an eine Aktion von einer abgefangenen Anfrage in PlayFramework übergeben?

+0

ein Attribut einstellen, weil in der funktionellen nicht verfügbar ist, sind wir in einer unveränderlichen Umgebung. Wenn Sie beispielsweise Sachen zu der Sitzung hinzufügen, erstellen Sie mit "withSession" eine "neue". Und im Kontext von onRouteRequest können Sie keine neue Anfrage erstellen, weil Sie nicht in der Lage sein werden, Ihrer zugrundeliegenden Aktion –

+0

+100, demselben Boot, ein Datenschnipsel zu geben, das in die Anfrage eingefügt wird, die für ALLE Routen/Aktionen gilt -Typen. Ich würde gerne die Datenberechnung an einem Ort machen, onRouteRequest, und dann irgendwo in der Anwendung, wo eine implizite Anfrage im Umfang ist, Zugriff auf die Daten haben (im Gegensatz zu re-f-ing es an verschiedenen Orten oder Hinzufügen von Boilerplate für jede Aktion, um es zu handhaben). – virtualeyes

+0

@andypetrella scala ist nicht rein funktional. Wir können Daten in die Komposition "Anfrage über Aktion" und "WrappedRequest" einfügen, wodurch die Post-Route der Anforderung effektiv geändert wird. Ich würde liebend gerne eine Platzhalter Map [String, String] in onRouteRequest setzen. Sie können die Anfrage kopieren und beispielsweise der Karte "Tags" auf dem RequestHeader einen Wert zuweisen. Spielen Sie natürlich, bläst Ihre wertvollen Daten weg, verwenden Sie die Tags Map für Routing-Ergebnisse (Controller-Methode, Typ GET, etc.) – virtualeyes

Antwort

2

Für Ihre Notwendigkeit, ich ding nicht mit der onRouteRequest wird funktionieren (elegant zumindest).

Aber versuchen wir, eine dedizierte Struktur zum Abfangen zu verwenden.

Hier ist, wie Sie die Anforderung abfangen könnte, einige generische Sachen berechnen und übergeben es an Aktion

Zunächst einmal ist hier ein Interceptor Objekt, das ein Verfahren intercept und eine bequeme Methode hat 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")) 

} 

Wie Sie sehen können, gibt Ihnen die Worker-Funktion intercept die Möglichkeit, basierend auf dem Inhalt der Anfrage einige Dinge zu berechnen. Welches Berechnungsergebnis vom Typ B fehlgeschlagen ist (Option), in diesem Fall ist ein Handler da, um zu sagen, was zu tun ist.

Nachdem definiert was zu berechnen, können Sie Ihre action mit einer Funktion, die eine B und gibt eine Action[A].

Die Methode username ist nur ein einfacher vordefinierter Interceptor, mit dem wir festlegen können, wie der angemeldete Benutzername abgerufen werden soll, um dies zu verdeutlichen.

Hier ist, wie wir beide in Ihrem 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)) 
    } 
    } 

Jetzt verwenden können, wenn Sie eine allgemeine Berechnung haben, können Sie Ihre vorkonfigurierte Interceptor erstellen (hier habe ich einen Fall, Klasse bin mit aber nur ein bestimmendes Funktion, die die interceptor gilt teilweise genügt)

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 auf den Kommentar bezogen werden:

entsprechend Ihren Kommentar, hier ist, wie Sie ein Interceptor mit tun könnte (man beachte, dass ich den Host-Abruf und Überprüfung verspottet)

Mit hosted und anotherHosted, Sie werden in der Lage sein, diesen Workflow zu testen:

  • /hosted/falsch? host = myhost => 404, weil auf den ersten myhost nicht zwischengespeichert und ich zur Verfügung gestellt falsch auf die geprüft Mockup
  • /hosted/true? host = myhost => nicht im Cache, aber es wird fügen Sie es hinzu, und dann keine 404
  • /gehostet/anotherHosted/false? Host = myhost => im Cache, weil es ist gehostet => nein 404
  • /gehostet/anotherHosted/false?host = notMyhost => 404

Hier ist der Code

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

Danke Andy, lassen Sie mich Ihnen sagen Im exakten Szenario erstelle ich eine gehostete Anwendung, für die sich Benutzer anmelden und ihre Domäne zuordnen können. Wenn ihre Benutzer/Kunden ihre zugeordnete Domäne erreichen, überprüft sie zunächst, ob die Domäne von uns gehostet wird, oder geben einen 404-Fehler zurück. Wenn die Domain gehostet wird, möchte ich die Site-Informationen an alle Aktionen weitergeben, damit ich sie nicht erneut in ihnen abrufe. – Aman

Verwandte Themen