虽然在很多关于go panic的文章里不推荐使用panic-recover处理业务异常,原因可能是在go早期,很少应用到业务系统中。

在业务系统中,错误码-错误信息是很重要的一部分。

如果使用err,一般会从问题现场return一直到业务入口处,如果层级特别深,则会造成比较大的成本,代码也会变得不够清晰。

使用panic则会规避以上情况,并且可以在业务入口处做到统一处理,简单直接规范错误码。


gin使用方式

实现`gin.HandlerFunc`, 并注册到gin里,如

func Recover() gin.HandlerFunc {
	return func(c *gin.Context) {
		defer func() {
			if r := recover(); r != nil {
				c.JSON(http.StatusOK, util.Struct2Map(r))
			}
		}()
		c.Next()
	}
}


	r := gin.Default()
	r.Use(Recover())


Go gRPC进阶-go-grpc-middleware使用

go-grpc-middleware封装了认证(auth), 日志( logging), 消息(message), 验证(validation), 重试(retries) 和监控(retries)等拦截器。

我们可以根据此扩展点处理所有的panic

var recoverHandler = func(next http.Handler) http.Handler {
	return http.HandlerFunc(
		func(w http.ResponseWriter, req *http.Request) {
			defer func() {
				if err := recover(); err != nil {

					if resultVO, ok := err.(vo.ResultVO); ok {
						body := &resultVO
						handleResultVO(w, body)
					} else {
						body := &vo.ResultVO{
							Errno:  500,
							Errmsg: util.Iface2string(err),
						}
						handleResultVO(w, body)
					}
				}
			}()
			next.ServeHTTP(w, req)
		},
	)
}


注册使用此recoverHandler

srv.AddHTTPMiddleware(recoverHandler)

另外,err通用处理也可以使用此方式

func errorHandler(ctx context.Context, mux *runtime.ServeMux, marshaler runtime.Marshaler, w http.ResponseWriter, r *http.Request, err error) {
	body := &vo.ResultVO{
		Errno:  500,
		Errmsg: err.Error(),
	}

	handleResultVO(w, body)
}