package middlewares
import (
"github.com/gin-gonic/gin"
"log"
"net/http"
)
func Recovery() gin.HandlerFunc {
return func(c *gin.Context) {
defer func() {
if r := recover(); r != nil {
log.Printf(" this panic: %v\n", r)
//如果后续没动作,c.AbortWithStatusJSON其实也可以,省去了return。
c.JSON(http.StatusInternalServerError, gin.H{
"code": "500",
"msg": errorToString(r),
"data": nil,
})
return
}
}()
c.Next()
}
}
func errorToString(r interface{}) string {
switch v := r.(type) {
case error:
return v.Error()
default:
return r.(string)
}
}
Gin统一异常处理中,自己中间件的异常不能通过这个Recovery中间件去捕获,无法返回我们希望给用户返回的500错误,不像是Spring可以全部捕获到,是因为有goroutine的存在,所以需要单独处理中间件的异常。
当前报错如下:
解决方案:
中间件单独加Defer,单独处理协程异常:
func Authorization() gin.HandlerFunc {
return func(c *gin.Context) {
defer func() {
if err := recover(); err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"code": "400",
"msg": "解析凭证异常",
"data": nil,
})
c.Abort()
}
}()
// ...... 你的鉴权逻辑
}
}
注意异常后Abort不再过后续的中间件,浪费请求资源了。
注意有结果abort后需要return防止拼成好几个json,abort只是中断后续中间件请求,不会终止当前函数,而且有异常就会走到if err := recover(); err != nil {}内,会返回2个JSON!
效果: