0

你能解释一下为什么小修改会完全破坏我的路由吗?

我的路由很简单

val myRoutes =
  pathPrefix("MainService") {
    post {
      requestInstance {
        request =>
          XmlBody {
            (command, payload) =>
              ifTrue2(command, "login") {
                complete {
                  "Return something here"    
                }
              } ~
                ifTrue2(command, "serverInfo") {
                  complete {
                    "Return something here"
                  }
                } ~
                extractSession(payload) { // OLD VERSION WAS: myAuthorization {
                  session =>
                    complete {
                      "Return something here"
                    }
                }
          }
      }

// Where custom directives look like this

def myAuthorization = entity(as[NodeSeq]).flatMap[Session :: HNil](
  getSession(_) match {
    case Some(session) => provide(session)
    case None => reject(AuthorizationFailedRejection)
  }
)

def extractSession(xmlPayload: ⇒ NodeSeq): Directive1[Session] =
  getSession(xmlPayload) match {
    case Some(session) => provide(session)
    case None => reject(AuthorizationFailedRejection)
  }

def ifTrue2(cmd : String, target : String): Directive0 =
  new Directive0 {
    def happly(func: HNil ⇒ Route) = {
      if (cmd.equalsIgnoreCase(target))
        func(HNil)
      else
        reject
    }
  }

def XmlBody = entity(as[NodeSeq]).flatMap[String :: Node :: HNil](
  parseXmlRequest(_) match {
    case Some(result) => hprovide(result)
    case None => reject(BadXmlRejection("Bad XML body"))
  }
)

def parseXmlRequest(xmlData: NodeSeq): Option[String :: Node :: HNil] = // body omitted for simplicity
def getSession(xmlRequest: NodeSeq): Option[Session] = // body omitted for simplicity

它支持两个未经身份验证的呼叫loginserverInfo. 所有其他请求必须在里面有 sessionId。

我在下面描述的情况发生在客户端仅发出一个登录请求时。

当我使用带有myAuthorization { }. 但它不适用于extractSession(payload) { }. myAuthorization隐式地HttpEntity作为输入。

最让我困惑的是,ifTrue2即使它们没有改变,指令也停止了工作。在调试器中,我看到它IfTrue2被调用了两次:使用("login", "login")("login", "serverInfo")参数。

为什么它的工作方式不同?我该怎么做才能修复它?

4

1 回答 1

0

关于新代码中的错误(导致异常):

实体指令从原始http-request 获取有效负载(它忽略hprovide- 因为它显然无法理解 hlist 并且仅适用于输入请求),您的新代码从parseXmlRequest. 这是唯一的区别。

简单地说 - 现在你打电话给像

 getSession(parseXmlRequest(request).payload) //it's now

代替

 getSession(request.as[NodeSeq]) //it was before

因此,<Envelope><Headers>...</><Body><function><param1>...<param1>...</></></>它不会<param1>...</>...传递给getSession并杀死您的 SOAP 授权(至少通过丢失 SOAP 标头和根标签),我认为会引发异常。

如果您想“更改”输入请求 - 使用mapRequest而不是hprovide


关于自定义指令的问题:

Spray计算所有 directives,但只计算一个合适的 s,complete因此您应该在自定义指令中捕获异常(任何地方的一个损坏的指令都可能会杀死您的整个路由):

def extractSession(xmlPayload: ⇒ NodeSeq): Directive1[Session] =
  try {
    getSession(xmlPayload) match {
      case Some(session) => provide(session)
      case None => reject(AuthorizationFailedRejection)
    }
  } catch {
    case t => reject(t)
  }
}

例子:

实际上我已经用这些模拟运行了你的代码:

  def parseXmlRequest(xmlData: NodeSeq): Option[String :: Node :: HNil] = {Some(xmlData.text :: <None/> :: HNil)}

  def getSession(xmlRequest: NodeSeq): Option[Session] = { Some(Session())}

并收到预期的结果。但是这些嘲笑:

  def parseXmlRequest(xmlData: NodeSeq): Option[String :: Node :: HNil] = {Some(xmlData.text :: <None/> :: HNil)}

  def getSession(xmlRequest: NodeSeq): Option[Session] = { sys.error("Error")}

将始终(即使对于登录命令)给您“InternalServerError”,因为您没有在指令中捕获异常。

于 2014-12-01T15:55:50.030 回答