2012-06-10 7 views
6

Estoy interceptando todas las solicitudes en mi aplicación de juego anulando el método onRouteRequest de GlobalSettings. Ahora, necesito enviar algunos datos a la acción enviada desde aquí para que no realice todos esos cálculos en todas las acciones. ¿Cómo configuro un atributo para el objeto request (play.api.mvc.RequestHeader) que paso al método super onRouteRequest?¿Cómo pasar una variable a una Acción desde una solicitud interceptada en PlayFramework?

+0

Configuración de un atributo no está disponible debido a que en funcional, estamos en un entorno inmutable. De modo que, al agregar cosas a la sesión, por ejemplo, se crea "una nueva" con 'withSession'. Y en el contexto de onRouteRequest no puede crear una nueva solicitud porque no podrá dar esta nueva a su acción subyacente –

+0

+100, misma embarcación, tiene un fragmento de datos para inyectar en la Solicitud que se aplica a TODAS las rutas/acciones -Tipos. Me gustaría hacer el cálculo de los datos en un solo lugar, onRouteRequest, y luego en cualquier lugar de la aplicación donde una solicitud implícita esté en el alcance, tenga acceso a los datos (frente a refinanciarlos, calcificándolos en varios lugares o añadiendo repetitivo para cada acción para manejarlo). – virtualeyes

+0

@andypetrella scala no es puramente funcional. Podemos inyectar datos en la solicitud a través de la composición de acción y WrappedRequest, modificando efectivamente la solicitud posterior a la ruta. Me encantaría un marcador de posición Map [String, String] para establecer en onRouteRequest. Puede copiar la solicitud y, por ejemplo, dar un valor al Mapa de "etiquetas" en el RequestHeader. Jugar, por supuesto, soplo sus datos preciosos, usando las etiquetas Mapa para los resultados de enrutamiento (método del controlador, tipo GET, etc.) – virtualeyes

Respuesta

2

Para su necesidad, no creo que el onRouteRequest funcione (elegantemente al menos).

Pero intentemos usar una estructura dedicada para interceptar.

Aquí es cómo se puede interceptar la petición, calcular algunas cosas genéricas y pasarlo a la acción

En primer lugar, aquí es un objeto Interceptor que tiene un método intercept y un método conveniente 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")) 

} 

Como puede ver, la función de trabajador intercept le da la oportunidad de calcular algunas cosas en función del contenido de la solicitud. Qué resultado de cálculo del tipo B podría fallar (Option), en ese caso, un controlador está allí para decir qué hacer.

Tener definido qué calcular, puede definir su action usando una función que toma un B y da un Action[A].

El método username es simplemente un simple interceptor predefinido que nos permite definir cómo recuperar el nombre de usuario registrado, solo para ilustrarlo.

Ahora aquí es cómo podemos utilizar los dos en su 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)) 
    } 
    } 

Ahora bien, si usted tiene un cálculo genérico puede crear su interceptor preconfigurado (en este caso estoy usando una clase de caso, sino simplemente definir una función que se aplica parcialmente el interceptor es suficiente)

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

EDITAR relacionado con el comentario:

consecuencia de su comentario, aquí es cómo se puede hacer usando un interceptor (tenga en cuenta que he burlado hasta la recuperación de acogida y la comprobación)

Usando hosted y anotherHosted, podrás poner a prueba este flujo de trabajo:

  • /alojada/falso? host = myhost => 404 porque al principio myhost no se almacena en caché y he proporcionado falsa a la maqueta comprobado
  • /alojada/verdad? host = myhost => no en caché, pero lo hará agréguelo, y luego no 404
  • /hosted/anotherHosted/false? host = myhost => en caché porque está alojado => no 404
  • /hosted/anotherHosted/false?host = notMyhost => 404

Este es el código

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

Gracias Andy, déjame decirte el escenario exacto, estoy construyendo una aplicación alojada a la cual los usuarios pueden registrarse y asignar su dominio. Cuando sus usuarios/clientes llegan a su dominio mapeado, primero verifica si el dominio está alojado por nosotros o devuelve un error 404. Si el dominio está alojado, quiero pasar la información del sitio a todas las acciones, para que no vuelva a buscarlo en ellas. – Aman

Cuestiones relacionadas