如何递归处理Akka HTTP路由

时间:2018-08-17 22:54:35

标签: akka akka-http

我有一个方案,其中路由包含键/值对的交替段。对的数量不确定,收集这些对的有效方法是什么。例如,路线可能看起来像

/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

如何定义可以递归添加数字的指令?任何帮助表示赞赏。

1 个答案:

答案 0 :(得分:2)

不要为键/值对使用路径

问题中描述的方法是一种反模式。在query string中,键/值配对可以轻松完成。通过使用parameterMap指令,将键/值对转换为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]

由于返回类型为Future,因此任何递归都必须是对原始Future的操作。因此,原始调用堆栈不能被忽略,并且递归将永远不会被尾部优化。如果路径足够长,则可能导致递归函数的堆栈溢出。

如果必须使用路径

如果除了使用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)
  }