后端的API从Java转到了Go,Go写起来言简意赅,很受欢迎。但Go带着C的风格,异常处理显得不够优雅。看了好几篇这方面的文章也没有一个满意的方案,后来自己做了一套方案,效果还可以,在这里介绍一下。

先看看Java的异常处理,在正常的程序流程里,一旦出现异常,就会马上终止原来的流程,把异常层层上报,直到异常被处理。程序里面就是 try -> throw -> catch -> finally 的过程。

再看C风格的异常处理,无论发生什么情况,函数都必须按照唯一的方式返回结果,所以很多函数在返回正常结果时还要额外返回一个error,收到这样的返回结果要先处理了error,再处理返回结果。代码里面到处是

if err != nil {
...
}

看着不美观,每次都要处理异常,调用的逻辑一旦复杂就容易失控了。

但很多文章总是强调panic是很危险的,会导致崩溃,error要分成各种各样等等。其实Go也提供了类似Java的异常处理机制,总结一下:

Java             Go
throw           panic
finally         defer
catch           recover

原来这样的func

func GetUser() (user User, err error)

其实这样写就好了,

func GetUser() (user User)

如果发生了异常情况,就直接panic(error),error的内容也可以自定义,调用的函数不需要特意去处理这个error,当成RuntimeException一样,这程序流程里面就不用到处写恶心的 if err != nil {...}

我们一般写的都是基于web的系统,只要加一个拦截器做异常处理,就不怕程序崩溃了。拦截器的核心内容就像这样

func Recover(ctx ) {
  defer func() {
      err := recover()
      if err != null {
         // handling error
      }()
  }
  // forward the request
  ctx.Next()
}

这个拦截器一般要第一个加载,保证整个request handling都有defer的覆盖。