首页 > 解决方案 > Akka - 声明一个隐式异常处理程序

问题描述

我创建了我的自定义异常处理程序,我希望它作为隐式对象工作,但是尽管在我的演员中抛出了异常,但它没有被调用。我从 API 获得了 OK 状态,而我应该收到无效模型的错误请求。

异常处理程序:

import akka.http.scaladsl.model.HttpResponse
import akka.http.scaladsl.server._
import Directives._
import akka.http.scaladsl.model.StatusCodes._
import regularmikey.credentials.exception.ValidationException

class CustomExceptionHandler {
  implicit def customExceptionHandler(): ExceptionHandler =
    ExceptionHandler {
      case _: ValidationException =>
        extractUri { uri =>
          println(s"Request to $uri could not be handled normally")
          complete(HttpResponse(BadRequest, entity = "There was a problem with validation"))
        }
    }
}

object CustomExceptionHandler extends CustomExceptionHandler

API 特征

import akka.actor.{ActorRef, Status}
import akka.actor.Status.Status
import akka.http.scaladsl.model.StatusCodes._
import akka.http.scaladsl.server.Directives._
import akka.http.scaladsl.server.{ExceptionHandler, Route}
import akka.pattern.ask
import akka.util.Timeout
import regularmikey.credentials.dto.RegisterRequest
import regularmikey.credentials.dto.RequestMarshaller._
import regularmikey.exception.CustomExceptionHandler

import scala.concurrent.{ExecutionContextExecutor, Future}

trait CredentialsApi {
  def createCredentialsActor(): ActorRef

  implicit def requestTimeout: Timeout
  implicit def executionContext: ExecutionContextExecutor

  implicit def exceptionHandler: ExceptionHandler = CustomExceptionHandler.customExceptionHandler()
  lazy val credentialsActor: ActorRef = createCredentialsActor()

  val credentialsRoute: Route =
    path("register") {
      post {
        pathEndOrSingleSlash {
          entity(as[RegisterRequest]) {
            request => {
              complete {
                val response: Future[Status] =
                  (credentialsActor ? request).mapTo[Status]
                OK
              }
            }
          }
        }
      }
    }
}

演员:

import akka.actor.{Actor, ActorLogging, Props, Status}
import akka.util.Timeout
import cats.data.Validated
import regularmikey.credentials.dto.RegisterRequest
import regularmikey.credentials.dto.validation.RegisterRequestValidatorNec
import regularmikey.credentials.exception.ValidationException

import scala.concurrent.Future

object CredentialsActor {
  def props(implicit timeout: Timeout) = Props(new CredentialsActor)
}

class CredentialsActor extends Actor with ActorLogging {
  def receive: Receive = {
    case RegisterRequest(userName, password, passwordRepeated) =>
      val result = RegisterRequestValidatorNec.validateRegisterRequest(userName, password, passwordRepeated)
      result match {
        case Validated.Valid(a) => sender() ! Status.Success
        case Validated.Invalid(e) => sender() ! Status.Failure(new ValidationException(e.toString))
      }
  }
}

class ValidationException(message: String) extends Exception

标签: scalaakkaactorakka-http

解决方案


theExceptionHandler被隐含地拾取,route2HandlerFlow这就是将 a 变成 aRoute的原因Flow[Request, Response, _]。这意味着如果您想隐式提供它,它需要在发生转换的地方可用,通常是在您调用bindAndHandle并将您的传递Route给它的地方,这会触发转换。

如果您希望将其作为Route定义的一部分,您可以使用显式handleExceptions指令(文档:https ://doc.akka.io/docs/akka-http/current/routing-dsl/directives/execution-指令/handleExceptions.html )


推荐阅读