1.定义Recover中间件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package handler

import (
    "awesomeProject/Result"
    "github.com/gin-gonic/gin"
    "log"
    "net/http"
    "runtime/debug"
)

func Recover(c *gin.Context) {
    defer func() {
        if r := recover(); r != nil {
            //打印错误堆栈信息
            log.Printf("panic: %v\n", r)
            debug.PrintStack()
            //封装通用json返回
            //c.JSON(http.StatusOK, Result.Fail(errorToString(r)))
            //Result.Fail不是本例的重点,因此用下面代码代替
            c.JSON(http.StatusOK, gin.H{
                "code": "1",
                "msg":  errorToString(r),
                "data": nil,
            })
            //终止后续接口调用,不加的话recover到异常后,还会继续执行接口里后续代码
            c.Abort()
        }
    }()
    //加载完 defer recover,继续后续接口调用
    c.Next()
}

// recover错误,转string
func errorToString(r interface{}) string {
    switch v := r.(type) {
    case error:
        return v.Error()
    default:
        return r.(string)
    }
}

2.使用Recover中间件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
func main() {
    router := gin.Default()
    //注意 Recover 要尽量放在第一个被加载
    //如不是的话,在recover前的中间件或路由,将不能被拦截到
    //程序的原理是:
    //1.请求进来,执行recover
    //2.程序异常,抛出panic
    //3.panic被 recover捕获,返回异常信息,并终止程序
    router.Use(handler.Recover)

    router.GET("/ping", func(c *gin.Context) {
        // 无意抛出 panic
        var slice = []int{1, 2, 3, 4, 5}
        slice[6] = 6
    })

    router.Run(":8080") // listen and serve on 0.0.0.0:8080 (for windows "localhost:8080")

}