Akka(32): Http:High-Level-Api,Route exception handling
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的更多相关文章
- Scalaz(32)- Free :lift - Monad生产线
在前面的讨论里我们提到自由数据结构就是产生某种类型的最简化结构,比如:free monoid, free monad, free category等等.我们也证明了List[A]是个free mono ...
- python(32)- 模块练习Ⅱ:使用正则表达式实现计算器的功能
开发一个简单的python计算器 实现加减乘除及拓号优先级解析 用户输入 1 - 2 * ( (60-30 +(-40/5) * (9-2*5/3 + 7 /3*99/4*2998 +10 * 568 ...
- Sharded实现学习-我们到底能走多远系列(32)
我们到底能走多远系列(32) 扯淡: 工作是容易的赚钱是困难的 恋爱是容易的成家是困难的 相爱是容易的相处是困难的 决定是容易的可是等待是困难的 主题: 1,Sharded的实现 Sharded ...
- Windows Phone开发(32):路径之PathGeometry
原文:Windows Phone开发(32):路径之PathGeometry 说起路径这玩意儿,其实说的就是Path类,它藏在命名空间System.Windows.Shapes下,应该好找,它有一个很 ...
- Akka(2):Actor生命周期管理 - 监控和监视
在开始讨论Akka中对Actor的生命周期管理前,我们先探讨一下所谓的Actor编程模式.对比起我们习惯的行令式(imperative)编程模式,Actor编程模式更接近现实中的应用场景和功能测试模式 ...
- Akka(6): become/unbecome:运算行为切换
通过一段时间的学习了解,加深了一些对Akka的认识,特别是对于Akka在实际编程中的用途方面.我的想法,或者我希望利用Akka来达到的目的是这样的:作为传统方式编程的老兵,我们已经习惯了直线流程方式一 ...
- Akka(8): 分布式运算:Remoting-远程查找式
Akka是一种消息驱动运算模式,它实现跨JVM程序运算的方式是通过能跨JVM的消息系统来调动分布在不同JVM上ActorSystem中的Actor进行运算,前题是Akka的地址系统可以支持跨JVM定位 ...
- Akka(33): Http:Marshalling,to Json
Akka-http是一项系统集成工具.这主要依赖系统之间的数据交换功能.因为程序内数据表达形式与网上传输的数据格式是不相同的,所以需要对程序高级结构化的数据进行转换(marshalling or se ...
- Akka(0):聊聊对Akka的初步了解和想法
前一段时间一直沉浸在函数式编程模式里,主要目的之一是掌握一套安全可靠的并发程序编程方法(concurrent programming),最终通过开源项目FunDA实现了单机多核CPU上程序的并行运算. ...
随机推荐
- 201521123026《JAVA程序设计》第14周学习总结
1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多数据库相关内容. 2. 书面作业 1. MySQL数据库基本操作 建立数据库,将自己的姓名.学号作为一条记录插入.(截图,需出现自 ...
- 201521044091 《Java程序设计》第12周学习总结
1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多流与文件相关内容. Answer: 2. 书面作业 将Student对象(属性:int id, String name,int a ...
- python基础之元组,集合
一.元组 为何要有元组,存放多个值,元组不可变,更多的是用来做查询 t=(,[,],,)) #t=tuple((,[,],,))) print(type(t)) 元组可以作为字典的key d={(,, ...
- mybatis-分页显示数据
分页用到的两个实体类 package com.yangwei.shop.entity; /** * 注意 get,set,remove 方法与一般的实体类的不同*/ public class Syst ...
- 关于XCode9的一些问题
最近几天一直在做一项工作,为新项目在做搭建框架的前期准备,然后恰逢更新iOS11和XCode9,笔者心急的尝了个先,发现了一些问题,记录一下,如果有相同问题的程序猿,也可以参考一下. 目前问题遇到两点 ...
- MyBatis框架(三)动态SQL,分页,二进制存入数据库图片
一.动态sql语句,分页 1, <if>条件 <if test="key!=null"> 拼接sql语句 </if> 2, <choose ...
- codeigniter 去除index.php (nginx,apache) 通用方法
.htaccess文件配置 1 <IfModule mod_rewrite.c> 2 RewriteEngine On 3 RewriteBase / 4 RewriteCond $1 ! ...
- SpringAop详解
近几天学习了一下SpringAop在网上找了一些资料,此链接为原文链接http://www.cnblogs.com/xrq730/p/4919025.html AOP AOP(Aspect Orien ...
- 记忆搜索与动态规划——DP背包问题
题目描述 01背包问题 有n个重量和价值分别为\(w_i,v_i\)的物品.从这些物品中挑选出总重量不超过W的物品,求所有挑选方案中价值中总和的最大值. 限制条件 1 <= n <= 10 ...
- java数据库编程之初始Mysql
2.3:命令行连接mySql 2.3.1:检查是否启动服务 步骤:计算机-----管理------服务和应用程序-------服务---搜索mysql右键启动服务 2.3.2:命令行方式连接数据库 步 ...