1

Akka HTTP 在路由 dsl 中很好地支持提取路径查询参数(那些在 ? 之后,由 & 连接的参数),但不支持由 ; 分隔的路径参数。(如 /my/path;JSESSIONID=123)

这如何最好地完成?

4

1 回答 1

2

比我想象的要容易。可能会消除对 scalaz (Lens) 的依赖并稍微优化代码,但现在就可以了。

顺便说一句,还发现路径参数破坏了将路径与路径指令匹配的能力:/my/path;JSESSIONID=123 与指令路径不匹配(“my”/“path”)

下面的解决方案通过从请求上下文中删除路径参数来解决这个问题,而是提供它们。

Akka 人注意:也许你可以在框架中加入类似的东西,这样下一个从路径参数中获取 JSESSIONID 的人不必实现相同的?

  def pathParams: Directive1[List[String]] = {
    val prv = provide(List.empty[String])
    def somePathParams(ctxPathLens: Lens[RequestContext, Path]) =
      extract(ctx => (Slash ~ Segments).apply(ctxPathLens.get(ctx))).flatMap {
        case Matched(_, Tuple1(path)) =>
          path.takeRight(1) match {
            case last :: Nil => last.split(';').toList match {
              case lastHead :: lastTail => provide(lastTail) & mapRequestContext(
                ctxPathLens.set(_, Path((path.dropRight(1) :+ lastHead).mkString("/", "/", ""))))
              case _ => prv
            }
            case _ => prv
          }
        case _ => prv
      }

    val unmatchedPath = somePathParams(Lens.lensu((ctx, path) =>
      ctx.mapUnmatchedPath(_ => path),
      _.unmatchedPath))

    val requestPath = somePathParams(Lens.lensu((ctx, path) =>
      ctx.mapRequest(r => r.withUri(r.uri.withPath(path)))
      , _.request.uri.path))

    unmatchedPath.tflatMap(_ => Directive.Empty) & requestPath
  }

  def pathParamsMap: Directive1[Map[String, String]] =
    pathParams.map(_.map(_.split('=').toList match {
      case key :: Nil => key -> ""
      case key :: values => key -> values.mkString("=")
      case _ => ???
    }).toMap)

  def optionalPathParam(name: String): Directive1[Option[String]] =
    pathParamsMap.map(_.get(name))

  def optionalPathParamSessionId:Directive1[Option[UUID]] =
    optionalPathParam(jsessionidKey).map(_.flatMap(j => Try(UUID.fromString(j)).toOption))
于 2015-08-18T09:09:47.057 回答