为什么 Akka HTTP 路由会捕获我的异常?

Why is Akka HTTP Routing Catching My Exception?

鉴于此代码

def leaderboardPost(name: Option[String]): Route =
  post {
    logRequest("leaderboard", Logging.DebugLevel) {
      handleRejections(postBodyRejections) {
        entity(as[LeaderboardPostRequest]) { leaderboard =>
          try {
            complete(leaderboardCreate(Some(leaderboard.name), Some(leaderboard.kind)))
          } catch {
            case cause: DuplicateIDException =>
              logger.error(cause)
              complete(cause.response)
            case cause: UnknownKindException =>
              logger.warn(cause)
              complete(cause.response)
            case cause: Throwable =>
              logger.error(cause)
              complete(HttpResponse(InternalServerError, entity = s"Exception thrown from LeaderboardPost: ${cause.getMessage}"))
          }
        }
      }
    }
  }

leaderboardCreate 抛出 UnknownKindException 路由代码捕获它并将其转换为 Completing with 500 Internal Server Error response. To change default exception handling behavior, provide a custom ExceptionHandler.

虽然我正在考虑创建自定义 ExceptionHandler,但我不明白为什么需要这样做。我的代码应该捕获它,而不是 return complete(cause.response)。 Akka HTTP 如何在我的代码捕获异常之前捕获异常?

根据我的理解,发生这种情况是因为 leaderboardCreate 实际上并未像您预期的那样与 complete 调用同步执行。 complete 方法 returns 扩展自 RouteStandardRoute 定义为:

type Route = RequestContext ⇒ Future[RouteResult]

换句话说,"route" 是从上下文到 FutureRouteResult)的函数。如果您查看 complete 定义,它就是:

def complete(m: ⇒ ToResponseMarshallable): StandardRoute =
  StandardRoute(_.complete(m))

注意 ToResponseMarshallable 之前的 。这是传递一个参数 by name 有效地将它变成惰性评估。

换句话说,你所有的 try/catch 包装都是非常小的(并且没有异常)构建 StandardRoute 的代码,它将你的逻辑捕获为惰性值,而不是逻辑本身的执行.这就是为什么你需要一个 custom ExceptionHandler ,你(或者更确切地说 Akka)实际上可以将它放入 Future 的错误处理程序链中,当它是 运行.