简体   繁体   中英

Playframework - Request[A] vs RequestHeader

I'm unable to understand diffrence between play.api.mvc.Request[A] and play.api.mvc.RequestHeader and play.api.mvc.Request[play.api.mvc.AnyContent] .


In compiled class I've got

def getLoginPage[A](implicit request: Request[A], form: Form[(String, String)], msg: Option[String]): Html = {
    val req = RequestWithUser(None, request)
    views.html.secure.login(form, msg)(request = req)
  }

Request[AnyContent] ---> RequestWithUser[play.api.mvc.AnyContent] ?

@(loginForm: play.api.data.Form[(String,String)], errorMsg: Option[String] = None)(implicit request: securesocial.core.RequestWithUser[_ <: play.api.mvc.AnyContent])

This code works in TemplatePlugin but it's not working in view:

type mismatch; found : securesocial.core.RequestWithUser[A] required: securesocial.core.RequestWithUser[_ <: play.api.mvc.AnyContent] 

It's not working because:

def getLoginPage[A](implicit request: Request[A], form: Form[(String, String)], msg: Option[String]): Html = {
    val req = RequestWithUser[play.api.mvc.AnyContent](None, request)
    views.html.secure.login(form, msg)(request = req)
  }

So I tried to put AnyContent as generic type:

type mismatch; found : play.api.mvc.Request[A] required: play.api.mvc.Request[play.api.mvc.AnyContent] 

But next compilation error shown:

package play.api.mvc
sealed trait AnyContent extends scala.AnyRef {
  def $init$() : scala.Unit = { /* compiled code */ }
  def asFormUrlEncoded : scala.Option[scala.Predef.Map[scala.Predef.String, scala.Seq[scala.Predef.String]]] = { /* compiled code */ }
  def asText : scala.Option[scala.Predef.String] = { /* compiled code */ }
  def asXml : scala.Option[scala.xml.NodeSeq] = { /* compiled code */ }
  def asJson : scala.Option[play.api.libs.json.JsValue] = { /* compiled code */ }
  def asMultipartFormData : scala.Option[play.api.mvc.MultipartFormData[play.api.libs.Files.TemporaryFile]] = { /* compiled code */ }
  def asRaw : scala.Option[play.api.mvc.RawBuffer] = { /* compiled code */ }
}

And play.api.mvc.AnyContent looks like:

 package play.api.mvc sealed trait AnyContent extends scala.AnyRef { def $init$() : scala.Unit = { /* compiled code */ } def asFormUrlEncoded : scala.Option[scala.Predef.Map[scala.Predef.String, scala.Seq[scala.Predef.String]]] = { /* compiled code */ } def asText : scala.Option[scala.Predef.String] = { /* compiled code */ } def asXml : scala.Option[scala.xml.NodeSeq] = { /* compiled code */ } def asJson : scala.Option[play.api.libs.json.JsValue] = { /* compiled code */ } def asMultipartFormData : scala.Option[play.api.mvc.MultipartFormData[play.api.libs.Files.TemporaryFile]] = { /* compiled code */ } def asRaw : scala.Option[play.api.mvc.RawBuffer] = { /* compiled code */ } } 

Please help me to solve this problem.


Edited - solution so far


I found code that compiles and even works well. Nevertheless this is not elegant way because I used asInstanceOf and cast class.

 def getLoginPage[A](implicit request: Request[A], form: Form[(String, String)], msg: Option[String]): Html = { implicit val r = RequestWithUser[play.api.mvc.AnyContent](None, request.asInstanceOf[Request[AnyContent]]) views.html.secure.login(form, msg)(request = r) } 

RequestHeader represents the header of the HTTP request. Request[A] is a RequestHeader plus a parsed request body of A . The default body parser in Play detects a few well known body formats ( application/json , application/xml , text/plain , application/x-www-form-urlencoded , multipart/form-data ), and parses them automatically into a body of type AnyContent , which then lets you access the specific types by calling methods such as asJson . If you write an action like:

def myAction = Action { req =>
  ...
}

Then the type of req will be Request[AnyContent] . On the other hand, if you explicitly specify a body parser, then the type of the request will be the type that that body parser returns, for example:

def myAction = Action(parse.json) { req =>
  ...
}

In that case, req will be Request[JsValue] . So, the secure social template wants a Request[AnyContent] , so firstly, this means you can only use it from actions that use the default body parser. Next, it means that you have to change the signature of your getLoginPage to only accept Request[AnyContent] , eg:

def getLoginPage(implicit request: Request[AnyContent], form: Form[(String, String)], msg: Option[String]): Html = {
  val req = RequestWithUser(None, request)
  views.html.secure.login(form, msg)(request = req)
}

That should work as is, as long as every action that invokes getLoginPage has a request that has been produced by the default body parser.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM