Akka(32): Http:High-Level-Api,Route exception handling
来源:互联网 发布:投诉淘宝卖家电话 编辑:程序博客网 时间:2024/05/21 16:21
Akka-http routing DSL在Route运算中抛出的异常是由内向外浮出的:当内层Route未能捕获异常时,外一层Route会接着尝试捕捉,依次向外扩展。Akka-http提供了ExceptionHandler类来处理Route运算产生的异常:
trait ExceptionHandler extends ExceptionHandler.PF { /** * Creates a new [[ExceptionHandler]] which uses the given one as fallback for this one. */ def withFallback(that: ExceptionHandler): ExceptionHandler /** * "Seals" this handler by attaching a default handler as fallback if necessary. */ def seal(settings: RoutingSettings): ExceptionHandler}object ExceptionHandler { type PF = PartialFunction[Throwable, Route] private[http] val ErrorMessageTemplate: String = { "Error during processing of request: '{}'. Completing with {} response. " + "To change default exception handling behavior, provide a custom ExceptionHandler." } implicit def apply(pf: PF): ExceptionHandler = apply(knownToBeSealed = false)(pf) private def apply(knownToBeSealed: Boolean)(pf: PF): ExceptionHandler = new ExceptionHandler { def isDefinedAt(error: Throwable) = pf.isDefinedAt(error) def apply(error: Throwable) = pf(error) def withFallback(that: ExceptionHandler): ExceptionHandler = if (!knownToBeSealed) ExceptionHandler(knownToBeSealed = false)(this orElse that) else this def seal(settings: RoutingSettings): ExceptionHandler = if (!knownToBeSealed) ExceptionHandler(knownToBeSealed = true)(this orElse default(settings)) else this } def default(settings: RoutingSettings): ExceptionHandler = apply(knownToBeSealed = true) { case IllegalRequestException(info, status) ⇒ ctx ⇒ { ctx.log.warning("Illegal request: '{}'. Completing with {} response.", info.summary, status) ctx.complete((status, info.format(settings.verboseErrorMessages))) } case NonFatal(e) ⇒ ctx ⇒ { val message = Option(e.getMessage).getOrElse(s"${e.getClass.getName} (No error message supplied)") ctx.log.error(e, ErrorMessageTemplate, message, InternalServerError) ctx.complete(InternalServerError) } } /** * Creates a sealed ExceptionHandler from the given one. Returns the default handler if the given one * is `null`. */ def seal(handler: ExceptionHandler)(implicit settings: RoutingSettings): ExceptionHandler = if (handler ne null) handler.seal(settings) else ExceptionHandler.default(settings)}
简单来说ExceptionHandler类型就是一种PartialFunction:
trait ExceptionHandler extends PartialFunction[Throwable, Route]
因为ExceptionHandler就是PartialFunction,所以我们可以用case XXException来捕获需要处理的异常。留下未捕获的异常向外层Route浮出。当未处理异常到达最外层Route时统一由最顶层的handler处理。与RejectionHandler一样,最顶层的handler是通过Route.seal设置的:
/** * "Seals" a route by wrapping it with default exception handling and rejection conversion. * * A sealed route has these properties: * - The result of the route will always be a complete response, i.e. the result of the future is a * ``Success(RouteResult.Complete(response))``, never a failed future and never a rejected route. These * will be already be handled using the implicitly given [[RejectionHandler]] and [[ExceptionHandler]] (or * the default handlers if none are given or can be found implicitly). * - Consequently, no route alternatives will be tried that were combined with this route * using the ``~`` on routes or the [[Directive.|]] operator on directives. */ def seal(route: Route)(implicit routingSettings: RoutingSettings, parserSettings: ParserSettings = null, rejectionHandler: RejectionHandler = RejectionHandler.default, exceptionHandler: ExceptionHandler = null): Route = { import directives.ExecutionDirectives._ // optimized as this is the root handler for all akka-http applications (handleExceptions(ExceptionHandler.seal(exceptionHandler)) & handleRejections(rejectionHandler.seal)) .tapply(_ ⇒ route) // execute above directives eagerly, avoiding useless laziness of Directive.addByNameNullaryApply }
上面的exceptionHandler没有默认值,看起来好像有可能有些异常在整个Route运算里都不会被捕获。但实际上Akka-http提供了默认的handler ExceptionHandler.default:
/** * Creates a sealed ExceptionHandler from the given one. Returns the default handler if the given one * is `null`. */ def seal(handler: ExceptionHandler)(implicit settings: RoutingSettings): ExceptionHandler = if (handler ne null) handler.seal(settings) else ExceptionHandler.default(settings)
通过这个ExceptionHandler.seal函数设置了最顶层的exception handler。
我们可以通过下面的方法来定制异常处理的方式:
自定义ExceptionHandler,然后:
1、把Exceptionhandler的隐式实例放在顶层Route的可视域内(implicit scope)
2、或者,直接调用handleExceptions,把自定义handler当作参数传入,把Route结构中间某层及其所有内层包嵌在handleExceptions中,例如:
val route: Route = get { pathSingleSlash { complete(HttpEntity(ContentTypes.`text/html(UTF-8)`,"<html><body>Hello world!</body></html>")) } ~ path("ping") { handleExceptions(customExceptionHandler) { onSuccess(Future.successful("ok")) complete("PONG!") } } ~ path("crash") { sys.error("BOOM!") } }
第一种办法是一种顶层对所有未捕获异常统一处理的方式,第二种办法可以限制处理区域针对某层以内的Route进行异常捕捉。
下面是第一种办法的使用示范:
object ExceptiontionHandlers { implicit def implicitExceptionHandler: ExceptionHandler = ExceptionHandler { case _: ArithmeticException => extractUri { uri => complete(HttpResponse(InternalServerError, entity = s"$uri: Bad numbers, bad result!!!")) } } def customExceptionHandler: ExceptionHandler = ExceptionHandler { case _: RuntimeException => extractUri { uri => complete(HttpResponse(InternalServerError, entity = s"$uri: Runtime exception!!!")) } }}
第二种方式的使用示范如下:
val route: Route = get { pathSingleSlash { complete(HttpEntity(ContentTypes.`text/html(UTF-8)`,"<html><body>Hello world!</body></html>")) } ~ path("ping") { onSuccess(Future.successful("ok")) complete("PONG!") } ~ handleExceptions(customExceptionHandler) { path("crash") { sys.error("BOOM!") } } }
下面是本次讨论中的示范源代码:
import akka.actor._import akka.http.scaladsl.Httpimport akka.http.scaladsl.model._import akka.http.scaladsl.server._import akka.http.scaladsl.server.Directives._import akka.stream._import StatusCodes._import scala.concurrent._object ExceptiontionHandlers { implicit def implicitExceptionHandler: ExceptionHandler = ExceptionHandler { case _: ArithmeticException => extractUri { uri => complete(HttpResponse(InternalServerError, entity = s"$uri: Bad numbers, bad result!!!")) } } def customExceptionHandler: ExceptionHandler = ExceptionHandler { case _: RuntimeException => extractUri { uri => complete(HttpResponse(InternalServerError, entity = s"$uriRuntime exception!!!")) } }}object ExceptionHandlerDemo extends App { import ExceptiontionHandlers._ implicit val httpSys = ActorSystem("httpSys") implicit val httpMat = ActorMaterializer() implicit val httpEc = httpSys.dispatcher val (port, host) = (8011,"localhost") val route: Route = get { pathSingleSlash { complete(HttpEntity(ContentTypes.`text/html(UTF-8)`,"<html><body>Hello world!</body></html>")) } ~ path("ping") { onSuccess(Future.successful("ok")) complete("PONG!") } ~ handleExceptions(customExceptionHandler) { path("crash") { sys.error("BOOM!") } } } val bindingFuture: Future[Http.ServerBinding] = Http().bindAndHandle(route,host,port) println(s"Server running at $host $port. Press any key to exit ...") scala.io.StdIn.readLine() bindingFuture.flatMap(_.unbind()) .onComplete(_ => httpSys.terminate())}
阅读全文
0 0
- Akka(32): Http:High-Level-Api,Route exception handling
- Akka(31): Http:High-Level-Api,Route rejection handling
- Akka(31): Http:High-Level-Api,Route rejection handling
- Akka(31): Http:High-Level-Api,Route rejection handling
- Akka(30): Http:High-Level-Api,Routing DSL
- Akka(30): Http:High-Level-Api,Routing DSL
- Akka(29): Http:Server-Side-Api,Low-Level-Api
- Akka(29): Http:Server-Side-Api,Low-Level-Api
- Akka(26): Stream:异常处理-Exception handling
- HIGH-LEVEL IOS HTTP APIS
- route,akka
- Akka(28): Http:About Akka-Http
- Akka(36): Http:Client-side-Api,Client-Connections
- Kafka High Level API vs. Low Level API
- Kafka High Level Consumer API in Scala
- kafka0.8 high-level consumer api使用
- Exception handling
- Exception Handling
- 读人人都是产品经理对产品经理的粗浅认识
- 数据蒋堂 | 非常规聚合
- 面试题
- 常用的小知识点
- python编程:电话簿TeleAddressBook和邮箱地址簿EmailAddressBook两个文件,合并为一个完整的AddressBook文件
- Akka(32): Http:High-Level-Api,Route exception handling
- 上传图片时,在页面进行预览
- android GLSurfaceView渲染模式
- 程序员眼中的 Eclipse
- 提高代码阅读能力的7种方法
- Coursera吴恩达《优化深度神经网络》课程笔记(2)-- 优化算法
- 国内IT界女神程序员!和她们一样漂亮的还有谁?
- 。。。。。
- sqoop 错误记录