关于微服务:微服务开发系列利用异常特性把异常纳入框架管理之中

42次阅读

共计 2613 个字符,预计需要花费 7 分钟才能阅读完成。

在零碎中,异样被分为了两种,一种是已知异样,一种是未知异样。

已知异样在框架中被封装为 cn.vte.framework.common.http.InnerExp,个别为业务异样,能够在任何接口拜访范畴内的代码内抛出。

InnerExp 作用

InnerExp 是为了可能灵便返回信息到前端,当办法的调用过多时或者逻辑嵌套过深,在满足条件时,不必一层一层返回,间接抛出异样即可把信息返回。

配合 GlobalMvcExceptionHandler 应用,该类拦挡了所有的 mvc http 接口异样,任何异样都会被解决成 RequestResult 构造。

InnerExp 特地的是,它会携带两种信息,一个是 RequestResult 还有一个是 Exception。这让 InnerExp 有更加灵便的性能。

InnerExp 携带 RequestResult 可能让返回的后果更加丰盛,开发人员能够自定义 RequestResult 的内容,甚至与返回失常的后果。

比方当你应用递归调用时,满足条件收集到了足够的信息时,抛出一个异样间接把后果返回,所以异样的应用不齐全是为了告诉程序异样了,灵便应用也可能解决失常的业务。

InnerExp 携带 Exception 时,GlobalMvcExceptionHandler 会判断 cause 是否为空,如果不为空就间接打印堆栈信息,帮忙排查问题,在业务代码遇见异样,并且不想解决时,间接交给最上层去做,有些时候会更加不便。

总结一下 InnerExp 的性能:

  1. 疾速抛出异样,将信息返回给前台,函数嵌套的状况下不必层层传递信息,并且可能携带实在异样,顶层打印堆栈信息。
  2. 疾速返回业务信息,同样不必层层传递。
  3. 继承 Supplier 接口,在流式解决中更加不便抛出异样。
  4. 利用 ifThr 传入条件判断是否应该抛出异样。

解决其它异样

在已知异样之外,其它异常情况的解决就绝对辣手一些,呈现什么品种的异样是齐全未知的。

你只能在产生某些异样的时候解决。

可能你会问,为什么不间接都当成一种状况解决呢?只有产生异样一律告知外部异样。

这样解决尽管简略,然而很多异样实际上不是后端逻辑谬误引擎的,更多的是数据校验方面的引起的,个别是因为前段发送数据不合乎后端的要求。

此时,你就要解决这种用异样,把他们整顿成前端开发人员,甚至是用户可能看懂的异样。

上面是框架中,所遇见过的一些异样类型解决。

1 ServiceUnavailable

因为 feign 调用不到的产生的异样。

框架会返回” 后盾服务未启动 ”的揭示。

2 HttpMessageNotReadableException

因为前端传入的 json 数据,无奈失常序列化为 java 对象产生的异样。

此异样解决的状况较为简单,因为解决异样自身不重要,更重要的是解决它携带的 cause

框架中解决了四种 cause

  1. InvalidFormatException
  2. MissingKotlinParameterException
  3. JsonMappingException
  4. 其它异样

1、2、3,实际上都为 jackson 所抛出的异样。

此处, 又是 jackson 的一大亮点,那就是你可能通过这些异样,来捕捉到 json 序列化的谬误地位。

因为这些异样,都携带有 getPath() 办法,可能找到嵌套的 json 谬误门路,于是框架中利用了这一点,来获取 jackson 序列化谬误的具体字段信息

fun List<JsonMappingException.Reference>.toPath(): String {val sb = StringBuilder()
    this.mapIndexed { index, reference ->
        sb.append(if (index == 0 || reference.fieldName == null) {reference.fieldName ?: "[${reference.index}]"
            } else {".${reference.fieldName}"
            }
        )
    }
    return sb.toString()}

举个例子,上面的这段代码,将会输入,a.type,来告知前端,a 对象下的 type 缺失。

data class A(val name: String, val type: String)
data class B(val name: String, val a: A)

val test = JacksonObject().put("name", "b").put("a", JacksonObject().put("name", "a"))
try {test.convert<B>()
} catch (e: IllegalArgumentException) {
    val cause = e.cause
    if (cause is MissingKotlinParameterException) {println(cause.path.toPath())
    }
}

除了下面的解决 JsonMappingException 还要独自拿进去解决,上面这段代码阐明了解决的思路

is JsonMappingException -> {
    val subCause = cause.cause
    if (subCause is InnerExp) {
        // 产生于 class init 抛出异样
        subCause.result
    } else if (subCause is DateTimeParseException) {RequestResult.error("""字段"{}"工夫值谬误:"{}"""", cause.path.toPath(), subCause.parsedString)
    } else {log.warn("{}", request.requestURI, exception)
        RequestResult.error("""字段"{}"值谬误:"{}"""", cause.path.toPath())
    }
}

这样解决异样的形式,很显著可能大大减少排查问题的难度。

3 NoHandlerFoundException

当地址找不到产生的异样,如果不解决,将返回 404。

4 MethodArgumentNotValidException

当 spring boot valid 校验失败产生的异样。

框架中,将会获取到校验失败的信息,而后以 RequestResult 的形式返回,缩小前端的解决工作。

如果不解决,前端是无奈获取到谬误的详细信息的,那么校验所能产生的作用就会大打折扣。

本文参加了思否技术征文,欢送正在浏览的你也退出。

正文完
 0