Gin - 错误处理
2025/12/30大约 1 分钟
Gin - 错误处理
统一响应格式
// 响应结构
type Response struct {
Code int `json:"code"`
Message string `json:"message"`
Data interface{} `json:"data,omitempty"`
}
// 成功响应
func Success(c *gin.Context, data interface{}) {
c.JSON(200, Response{
Code: 0,
Message: "success",
Data: data,
})
}
// 错误响应
func Error(c *gin.Context, code int, message string) {
c.JSON(200, Response{
Code: code,
Message: message,
})
}业务错误
// 自定义业务错误
type BizError struct {
Code int
Message string
}
func (e *BizError) Error() string {
return e.Message
}
// 预定义错误
var (
ErrNotFound = &BizError{404, "资源不存在"}
ErrUnauthorized = &BizError{401, "未授权"}
ErrForbidden = &BizError{403, "禁止访问"}
ErrBadRequest = &BizError{400, "请求参数错误"}
)
// 错误处理中间件
func ErrorHandler() gin.HandlerFunc {
return func(c *gin.Context) {
c.Next()
// 获取错误
if len(c.Errors) > 0 {
err := c.Errors.Last().Err
if bizErr, ok := err.(*BizError); ok {
c.JSON(200, Response{
Code: bizErr.Code,
Message: bizErr.Message,
})
} else {
c.JSON(500, Response{
Code: 500,
Message: "服务器内部错误",
})
}
}
}
}自定义 Recovery
func CustomRecovery() gin.HandlerFunc {
return func(c *gin.Context) {
defer func() {
if err := recover(); err != nil {
// 记录错误日志
log.Printf("Panic: %v\n%s", err, debug.Stack())
c.JSON(500, Response{
Code: 500,
Message: "服务器内部错误",
})
c.Abort()
}
}()
c.Next()
}
}
r.Use(CustomRecovery())优雅关闭
func main() {
r := gin.Default()
// 配置路由...
srv := &http.Server{
Addr: ":8080",
Handler: r,
}
go func() {
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
log.Fatalf("listen: %s\n", err)
}
}()
// 等待中断信号
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
<-quit
log.Println("Shutdown Server ...")
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := srv.Shutdown(ctx); err != nil {
log.Fatal("Server forced to shutdown:", err)
}
log.Println("Server exiting")
}