记录一下如何利用recover
和gin
中间件来优雅的实现异常处理
首先是中间件的实现:
package exception
import (
"github.com/gin-gonic/gin"
"log"
"net/http"
)
type Api struct {
Code int
Message string
}
// Handler 异常处理
func Handler(c *gin.Context) {
defer func() {
if r := recover(); r != nil {
switch t := r.(type) {
case *Api:
log.Printf("panic: %v\n", t.Message)
c.JSON(t.Code, gin.H{
"message": t.Message,
})
default:
log.Printf("panic: internal error")
c.JSON(http.StatusInternalServerError, gin.H{
"message": "服务器内部异常",
})
}
c.Abort()
}
}()
c.Next()
}
在路由初始化后紧接着加入该中间件:
router = gin.Default() router.Use(exception.Handler)
使用案例,如在处理数据库异常时:
func (appUser *AppUser) Create() {
if err := db.DB.Create(&appUser).Error; err != nil {
// 数据库写入失败
panic(&exception.Api{Code: http.StatusInternalServerError, Message: err.Error()})
}
}
又或者是在业务逻辑中:
// 账号密码校验
if hasRecord && bcrypt.CompareHashAndPassword(appUser.Password, inputPassword) != nil {
panic(&exception.Api{Code: http.StatusUnauthorized, Message: "密码错误"})
}
通过这种方式可以减少大量判断err
做if else
的逻辑,非常好用