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-)`,"<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-)`,"<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.Http
import 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) = (,"localhost") val route: Route =
get {
pathSingleSlash {
complete(HttpEntity(ContentTypes.`text/html(UTF-)`,"<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()) }

Akka(32): Http:High-Level-Api,Route exception handling的更多相关文章

  1. Scalaz(32)- Free :lift - Monad生产线

    在前面的讨论里我们提到自由数据结构就是产生某种类型的最简化结构,比如:free monoid, free monad, free category等等.我们也证明了List[A]是个free mono ...

  2. python(32)- 模块练习Ⅱ:使用正则表达式实现计算器的功能

    开发一个简单的python计算器 实现加减乘除及拓号优先级解析 用户输入 1 - 2 * ( (60-30 +(-40/5) * (9-2*5/3 + 7 /3*99/4*2998 +10 * 568 ...

  3. Sharded实现学习-我们到底能走多远系列(32)

    我们到底能走多远系列(32) 扯淡: 工作是容易的赚钱是困难的 恋爱是容易的成家是困难的 相爱是容易的相处是困难的 决定是容易的可是等待是困难的 主题: 1,Sharded的实现    Sharded ...

  4. Windows Phone开发(32):路径之PathGeometry

    原文:Windows Phone开发(32):路径之PathGeometry 说起路径这玩意儿,其实说的就是Path类,它藏在命名空间System.Windows.Shapes下,应该好找,它有一个很 ...

  5. Akka(2):Actor生命周期管理 - 监控和监视

    在开始讨论Akka中对Actor的生命周期管理前,我们先探讨一下所谓的Actor编程模式.对比起我们习惯的行令式(imperative)编程模式,Actor编程模式更接近现实中的应用场景和功能测试模式 ...

  6. Akka(6): become/unbecome:运算行为切换

    通过一段时间的学习了解,加深了一些对Akka的认识,特别是对于Akka在实际编程中的用途方面.我的想法,或者我希望利用Akka来达到的目的是这样的:作为传统方式编程的老兵,我们已经习惯了直线流程方式一 ...

  7. Akka(8): 分布式运算:Remoting-远程查找式

    Akka是一种消息驱动运算模式,它实现跨JVM程序运算的方式是通过能跨JVM的消息系统来调动分布在不同JVM上ActorSystem中的Actor进行运算,前题是Akka的地址系统可以支持跨JVM定位 ...

  8. Akka(33): Http:Marshalling,to Json

    Akka-http是一项系统集成工具.这主要依赖系统之间的数据交换功能.因为程序内数据表达形式与网上传输的数据格式是不相同的,所以需要对程序高级结构化的数据进行转换(marshalling or se ...

  9. Akka(0):聊聊对Akka的初步了解和想法

    前一段时间一直沉浸在函数式编程模式里,主要目的之一是掌握一套安全可靠的并发程序编程方法(concurrent programming),最终通过开源项目FunDA实现了单机多核CPU上程序的并行运算. ...

随机推荐

  1. Shiro第三篇【授权、自定义reaml授权】

    Shiro授权 上一篇我们已经讲解了Shiro的认证相关的知识了,现在我们来弄Shiro的授权 Shiro授权的流程和认证的流程其实是差不多的: Shiro支持的授权方式 Shiro支持的授权方式有三 ...

  2. Struts2第二篇【开发步骤、执行流程、struts.xml讲解、defalut-struts讲解】

    前言 我们现在学习的是Struts2,其实Struts1和Struts2在技术上是没有很大的关联的.Struts2其实基于Web Work框架的,只不过它的推广没有Struts1好,因此就拿着Stru ...

  3. weblogic服务器上类或者方法找不到的解决办法

    下面以eclipse-birt(报表)为例,介绍这种问题出现的原因以及解决之道: 分析比较好的见:http://developer.actuate.com/community/forum/index. ...

  4. OpenStack Ocata 超详细搭建文档

    前言 搭建前必须看我本文档搭建的是分布式O版openstack(controller+ N compute + 1 cinder)的文档.openstack版本为Ocata.搭建的时候,请严格按照文档 ...

  5. AngularJS的运用

      前  言 JRedu AngularJS[1]  诞生于2009年,由Misko Hevery 等人创建,后为Google所收购.是一款优秀的前端JS框架,已经被用于Google的多款产品当中.A ...

  6. oracle数据中记录被另一个用户锁住

    原因:PL/SQL里面执行语句执行了很久都没有结果,于是中断执行,于是就直接在上面改字段,在点打钩(记入改变)的时候提示,记录被另一个用户锁住. 解决方法: 第一步:(只是用于查看哪些表被锁住,真正有 ...

  7. bzoj1968 COMMON 约数研究

    Input只有一行一个整数 N(0 < N < 1000000).Output只有一行输出,为整数M,即f(1)到f(N)的累加和.Sample Input 3 Sample Output ...

  8. CentOS 7搭建LAMP环境(二)

    前面已经讲过了CentOS 7下LAMP环境的配置过程,一台简单的WEB服务器已搭建完成,但后期在网站部署的过程中也许会碰到各种各样头疼的问题.下面我们来讲讲怎么解决这些问题,以及如何高效地管理服务器 ...

  9. java递归的应用和实例

    使用计算机计算组合数: 1.使用组合数公式利用n!来计算 设计思想 (1)首先解决求n!的函数 (2)再结合组合数公式,求组合数 程序流程图 源程序代码 package Zuote; import j ...

  10. FPGA在AD采集中的应用

    AD转换,也叫模数转换,是将模拟信号转换为数字信号.目前包括电脑CPU,ARM,FPGA,处理的信号都只能是数字信号,所以数据信号在进入处理芯片前必须要进行AD转换. 在高速的AD转换中,FPGA以其 ...