【问题标题】:Playframework - Request[A] vs RequestHeaderPlayframework - Request[A] vs RequestHeader
【发布时间】:2013-12-03 07:42:04
【问题描述】:

我无法理解 play.api.mvc.Request[A]play.api.mvc.RequestHeaderplay.api.mvc.Request[play.api.mvc.AnyContent] 之间的差异。


在编译类我有
trait Request[+A] extends scala.AnyRef with play.api.mvc.RequestHeader {
  def $init$() : scala.Unit = { /* compiled code */ }
  def body : A
  def map[B](f : scala.Function1[A, B]) : play.api.mvc.Request[B] = { /* compiled code */ }
}
object Request extends scala.AnyRef {
  def apply[A](rh : play.api.mvc.RequestHeader, a : A) : scala.AnyRef with play.api.mvc.Request[A] {
  val remoteAddress : scala.Predef.String
  def username : scala.None.type
  val body : A
} = { /* compiled code */ }
}

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

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

此代码在 TemplatePlugin 中有效,但在视图中无效:

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

它不起作用,因为:

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

所以我尝试将AnyContent 作为泛型类型:

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

但显示下一个编译错误:

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

play.api.mvc.AnyContent 看起来像:

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 */ }
}

请帮我解决这个问题。


已编辑 - 到目前为止的解决方案


我发现可以编译甚至运行良好的代码。尽管如此,这不是优雅的方式,因为我使用了asInstanceOf 和演员班。
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)
  }

【问题讨论】:

    标签: scala playframework playframework-2.0


    【解决方案1】:

    RequestHeader 表示 HTTP 请求的标头。 Request[A]RequestHeader 加上已解析的请求正文 A。 Play 中的默认正文解析器会检测一些众所周知的正文格式(application/jsonapplication/xmltext/plainapplication/x-www-form-urlencodedmultipart/form-data),并自动将它们解析为 AnyContent 类型的正文,然后允许您通过调用诸如asJson 之类的方法来访问特定类型。如果您编写如下操作:

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

    那么req 的类型将是Request[AnyContent]。另一方面,如果你显式指定了一个正文解析器,那么请求的类型将是该正文解析器返回的类型,例如:

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

    在这种情况下,req 将是 Request[JsValue]。因此,安全社交模板需要Request[AnyContent],因此首先,这意味着您只能在使用默认正文解析器的操作中使用它。接下来,这意味着您必须将getLoginPage的签名更改为仅接受Request[AnyContent],例如:

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

    只要调用 getLoginPage 的每个操作都有一个由默认正文解析器生成的请求,它就应该按原样工作。

    【讨论】:

    • 一件事——方法签名不能改变:/
    • 为什么不能改签名?另外,模板是你写的吗?如果你这样做了,那你为什么不改变模板的签名来接受 Request[_] 呢?如果模板必须接收 AnyContent 类型的内容,那么这意味着它将尝试以某种方式使用主体,这意味着强制转换可能会导致运行时错误。
    • 我写了模板,但是模板必须是这样的,因为main.scala.html的参数是一样的。我也无法更改方法签名,因为它是 SecureSocial 的一部分,并且有一个插件 TemplatePlugin 必须实现才能正常工作。
    • 如果主模板采用RequestHeader,那么没有什么能阻止您将Request[AnyContent] 传递给它,因为Request 扩展了RequestHeader
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-10-22
    • 2015-11-24
    • 2012-07-26
    • 2020-07-07
    • 2018-11-20
    • 2015-01-31
    • 1970-01-01
    相关资源
    最近更新 更多