您能否解释一下为什么小修改会完全破坏我的路由?
我的路由非常简单
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
它支持两个未经身份验证的调用login
和serverInfo
。所有其他请求必须在其中包含sessionId。
当客户端只有一个登录请求时,我会在下面介绍。
当我使用myAuthorization { }
版本时,提供的代码适用于登录请求。但它不适用于extractSession(payload) { }
。 myAuthorization
明确地将HttpEntity
作为输入。
最令我困惑的是ifTrue2
下的指令即使没有改变也停止了工作。在调试器中,我看到IfTrue2
按预期调用了两次:使用("login", "login")
和("login", "serverInfo")
参数。
为什么它的工作方式不同?我该怎么做才能解决它?
答案 0 :(得分:0)
关于新代码中的错误(导致异常):
entity指令从原始http请求中获取有效负载(它忽略了hprovide
的结果 - 因为它显然无法理解hlists并且仅适用于输入请求),您的新代码需要它来自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标头和根标签),我认为会引发异常。< / p>
如果你想改变&#39;输入请求 - 使用mapRequest
代替hprovide
关于自定义指令的问题:
Spray
计算所有 directive
,但只有一个适当的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")}
将始终(即使对于登录命令)给你&#34; InternalServerError&#34;因为你没有在指令中捕获异常。