如何递归处理 Akka HTTP 路由
How to handle an Akka HTTP route recursively
我有一个场景,其中路线包含 key/value 对的交替段。对的数量未定义,收集这些对的有效方法是什么。例如,路线可能看起来像
/key1/value1/key2/value2/key3/value3
我想得到一个链接图
(key1, value1) -> (key2, value2) -> (key3, value3)
我知道我们可以获取路径段列表并按上述方式进行转换。但我正在寻找的是像
这样的导航路径
class EntitiesSpec extends WordSpec with Matchers with ScalatestRouteTest with Directives {
def lastSegment:Directive1[String] = path(Segment)
def intermediate: Directive1[String] = <processing the intermediate>
val navigate = (intermediate & navigate) ~ lastSegment
val route = navigate { (param1:String) =>
complete(param1)
}
"this should call the route" should {
"invoke a route /hello" in {
Get("/hello/world/hello1/world1/hello3/world3") ~> route ~> check {
println(responseAs[String])
}
}
}
}
另一个好的方法是,例如,如果你有一条像
这样的路径
/12/1/5/6/8
如何定义可以递归相加的指令?感谢任何帮助。
不要为 Key/Value 对使用路径
问题中描述的方法是一种反模式。 Key/value 配对可以在 query string. By using the parameterMap
指令中更容易完成,将 key/value 对转换为 String
元组列表变得微不足道:
//matches a uri of the form: /?key1=value1&key2=value2
val queryStringRoute =
parameterMap { params =>
val linkedPairList : List[(String, String)] = params.toList
}
不要对指令使用递归
递归指令也是不明智的。 A Route
is declared as a simple Function1
:
type Route = (RequestContext) ⇒ Future[RouteResult]
因为 return 类型是 Future
那么任何递归都必须是对原始 Future 的操作。因此,原始调用栈不能被忽略,递归永远不会尾部优化。如果 Path 足够长,可能会导致递归函数的计算溢出。
如果必须使用路径
当你别无选择只能使用 Path
那么你可以做一些 String
解析:
val pathToKeyValuePairs : Uri.Path => List[(String, String)] =
(_ : Uri.Path)
.toString
.split('/')
.grouped(2)
.map(arr => arr(0) -> arr(1))
.toList
现在可以在 Route
:
中使用此解析器
val unadvisedRoute =
extractRequest { request =>
val linkedPairList : List[(String, String)] =
pathToKeyValuePairs(request.uri.path)
}
我有一个场景,其中路线包含 key/value 对的交替段。对的数量未定义,收集这些对的有效方法是什么。例如,路线可能看起来像
/key1/value1/key2/value2/key3/value3
我想得到一个链接图
(key1, value1) -> (key2, value2) -> (key3, value3)
我知道我们可以获取路径段列表并按上述方式进行转换。但我正在寻找的是像
这样的导航路径class EntitiesSpec extends WordSpec with Matchers with ScalatestRouteTest with Directives {
def lastSegment:Directive1[String] = path(Segment)
def intermediate: Directive1[String] = <processing the intermediate>
val navigate = (intermediate & navigate) ~ lastSegment
val route = navigate { (param1:String) =>
complete(param1)
}
"this should call the route" should {
"invoke a route /hello" in {
Get("/hello/world/hello1/world1/hello3/world3") ~> route ~> check {
println(responseAs[String])
}
}
}
}
另一个好的方法是,例如,如果你有一条像
这样的路径/12/1/5/6/8
如何定义可以递归相加的指令?感谢任何帮助。
不要为 Key/Value 对使用路径
问题中描述的方法是一种反模式。 Key/value 配对可以在 query string. By using the parameterMap
指令中更容易完成,将 key/value 对转换为 String
元组列表变得微不足道:
//matches a uri of the form: /?key1=value1&key2=value2
val queryStringRoute =
parameterMap { params =>
val linkedPairList : List[(String, String)] = params.toList
}
不要对指令使用递归
递归指令也是不明智的。 A Route
is declared as a simple Function1
:
type Route = (RequestContext) ⇒ Future[RouteResult]
因为 return 类型是 Future
那么任何递归都必须是对原始 Future 的操作。因此,原始调用栈不能被忽略,递归永远不会尾部优化。如果 Path 足够长,可能会导致递归函数的计算溢出。
如果必须使用路径
当你别无选择只能使用 Path
那么你可以做一些 String
解析:
val pathToKeyValuePairs : Uri.Path => List[(String, String)] =
(_ : Uri.Path)
.toString
.split('/')
.grouped(2)
.map(arr => arr(0) -> arr(1))
.toList
现在可以在 Route
:
val unadvisedRoute =
extractRequest { request =>
val linkedPairList : List[(String, String)] =
pathToKeyValuePairs(request.uri.path)
}