2

在这里回答我自己的问题,因为这花了我一天的时间才弄清楚,这是一个非常简单的问题,我认为其他人可能会遇到。

在使用 Spray 创建的 RESTful-esk 服务时,我想匹配路径中包含字母数字 id 的路由。这是我最初开始的:

case class APIPagination(val page: Option[Int], val perPage: Option[Int])
get {
  pathPrefix("v0" / "things") {
    pathEndOrSingleSlash {
      parameters('page ? 0, 'perPage ? 10).as(APIPagination) { pagination =>
        respondWithMediaType(`application/json`) {
          complete("things")
        }
      }
    } ~ 
    path(Segment) { thingStringId =>
      pathEnd {
        complete(thingStringId)
      } ~
      pathSuffix("subthings") {
        pathEndOrSingleSlash {
          complete("subthings")
        }
      } ~
      pathSuffix("othersubthings") {
        pathEndOrSingleSlash {
          complete("othersubthings")
        }
      } 
    }
  }
} ~ //more routes...

这在编译时没有问题,但是当使用 scalatest 验证路由结构是否正确时,我惊讶地发现这种类型的输出:

"ThingServiceTests:"
"Thing Service Routes should not reject:"
- should /v0/things
- should /v0/things/thingId
- should /v0/things/thingId/subthings *** FAILED ***
  Request was not handled (RouteTest.scala:64)
- should /v0/things/thingId/othersubthings *** FAILED ***
  Request was not handled (RouteTest.scala:64)

我的路线有什么问题?

4

1 回答 1

5

我查看了许多资源,例如这个 SO Question这个博客文章,但似乎找不到任何关于使用字符串 Id 作为路由结构的顶级部分的信息。在发现这个重要的测试之前,我查看了喷雾 scaladoc在路径匹配器上的文档中打了一会儿头(重复如下)

"pathPrefix(Segment)" should {
    val test = testFor(pathPrefix(Segment) { echoCaptureAndUnmatchedPath })
    "accept [/abc]" in test("abc:")
    "accept [/abc/]" in test("abc:/")
    "accept [/abc/def]" in test("abc:/def")
    "reject [/]" in test()
  }

这让我知道了几件事。我应该尝试使用pathPrefix而不是path. 所以我改变了我的路线看起来像这样:

get {
  pathPrefix("v0" / "things") {
    pathEndOrSingleSlash {
      parameters('page ? 0, 'perPage ? 10).as(APIPagination) { pagination =>
        respondWithMediaType(`application/json`) {
          listThings(pagination)
        }
      }
    } ~ 
    pathPrefix(Segment) { thingStringId =>
      pathEnd {
        showThing(thingStringId)
      } ~
      pathPrefix("subthings") {
        pathEndOrSingleSlash {
          listSubThingsForMasterThing(thingStringId)
        }
      } ~
      pathPrefix("othersubthings") {
        pathEndOrSingleSlash {
          listOtherSubThingsForMasterThing(thingStringId)
        }
      } 
    }
  }
} ~

并且很高兴我的所有测试都通过并且路线结构正常工作。然后我将其更新为使用Regex匹配器:

pathPrefix(new scala.util.matching.Regex("[a-zA-Z0-9]*")) { thingStringId =>

并决定为遇到类似问题的其他人发布 SO。正如 jrudolph 在评论中指出的那样,这是因为Segment期望匹配<Segment><PathEnd>而不是在路径中间使用。哪个pathPrefix更有用

于 2015-08-03T16:16:05.613 回答