我有以下路由定义
private val routes: Route =
concat(
pathEnd {
get {
handleErrorsAndReport("list_foos") {
}
}
},
path(Segment) { fooId =>
get {
handleErrorsAndReport("get_foo") {
rejectEmptyResponse(
complete(service.do(fooId))
)
}
}
},
pathEnd {
authenticateBasic(
realm = "Secure scope",
scopesAuthenticator
) { scopes =>
post {
handleErrorsAndReport("create_foo") {
}
}
}
},
path(Segment) { fooId =>
authenticateBasic(
realm = "Secure scopes",
scopesAuthenticator
) { scopes =>
concat(
put {
handleErrorsAndReport("update_foo") {
}
},
delete {
handleErrorsAndReport("delete_foo") {
}
}
)
}
}
)
我正在尝试使用get_foo
终结点。我已经为此创建了一个单元测试,它看起来像这样
"allow get operation on foo without authentication present" in {
Get("/foos/{some_id}") ~> routes ~> check {
status shouldBe StatusCodes.NotFound
}
}
在调试测试时,我可以看到路由被正确识别,并且我可以访问路由内的代码。get_foo
路由内的服务代码生成None,complete(None)
创建拒绝,因为它是一个空响应,并且我有rejectEmptyResponse
指令。因此,我希望根据我定义的handleErrorsAndReport
指令得到一个404响应。
private def handleErrorsAndReport(endpoint: String): Directive0 = extractRequestContext.flatMap { ctx =>
val start = System.currentTimeMillis()
mapResponse { resp =>
// store response related metrics and return response
resp
} & handleExceptions(exceptionHandler)
}
private val exceptionHandler: ExceptionHandler = {
def handle(e: Throwable, responseCode: StatusCode, errorMessage: Option[String]): Route = {
extractRequest { request =>
val response = (responseCode, errorMessage) match {
case (InternalServerError, _) => "Internal Server Error"
case (_, Some(message)) => message
case _ => "Bad Request"
}
complete(HttpResponse(responseCode, entity = response))
}
}
ExceptionHandler {
case e@AError(description) => handle(e, BadRequest, Some(description))
case e: BError => handle(e, InternalServerError, Some(e.errorMessage))
case e: CError => handle(e, BadRequest, Some(e.errorMessage))
case e: DError => handle(e, BadRequest, Some(e.errorMessage))
case e: EError => handle(e, BadRequest, Some(e.errorMessage))
case e@FException(filter) => handle(e, BadRequest, Some(s"bla"))
case other => handle(other, InternalServerError, Option(other.getMessage))
}
}
我得到的是一个401未经授权。这怎么可能呢?当我在调试代码时,我注意到控制流从来没有进入我的异常处理程序-我在里面到处添加了断点...
1条答案
按热度按时间bn31dyow1#
您的代码的问题在于,在拒绝了unauthenticated指令中的请求后,匹配发生在具有相同url的已验证路由上。因此,验证失败并导致401 unauthorized而不是404。
为了解决这个问题,您需要在使用
GET
方法的未经身份验证的路由失败后,通过将其 Package 在post
、put
和delete
路由内,使GET
请求无法到达它,从而防止与经过身份验证的路由的这种匹配。所以它可以写成