Почему Akka HTTP Routing перехватывает мое исключение? - PullRequest
0 голосов
/ 23 января 2019

С учетом этого кода

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, я не понимаю, зачем мне это нужно. Мой код должен его перехватить и вернуть вместо него complete(cause.response). Как Akka HTTP перехватывает исключение до того, как мой код это делает?

1 Ответ

0 голосов
/ 23 января 2019

Согласно моему пониманию, это происходит потому, что leaderboardCreate на самом деле не выполняется синхронно с вызовом complete, как вы могли ожидать. Метод complete возвращает StandardRoute, который начинается с Route и определяется как:

type Route = RequestContext ⇒ Future[RouteResult]

Другими словами, «маршрут» - это функция из контекста в Future (из RouteResult). И если вы посмотрите на определение complete, это просто:

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

Обратите внимание на перед ToResponseMarshallable. Это передает параметр по имени , который фактически превращает его в ленивую оценку.

Другими словами, все ваши обертки try/catch - это очень маленький (и свободный от исключений) код построения StandardRoute, который фиксирует вашу логику как ленивое значение, но не выполнение самой логики. Вот почему вам нужен пользовательский ExceptionHandler , который вы (или, скорее, Akka) фактически можете поместить в цепочку обработчиков ошибок для Future, когда он будет запущен.

...