中间件错误处理
中间件是统一错误处理的最佳位置,可以实现集中式的错误响应。
c.Error 记录错误
Go
func handler(c *gin.Context) {
if err := doSomething(); err != nil {
c.Error(err) // 记录错误,不终止请求
}
c.JSON(200, gin.H{"status": "ok"})
}
收集错误统一处理
Go
func errorHandlerMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
c.Next() // 执行后续处理
// 收集所有错误
if len(c.Errors) > 0 {
errors := make([]string, 0)
for _, e := range c.Errors {
errors = append(errors, e.Error())
}
c.JSON(500, gin.H{
"code": 500,
"message": "处理过程中发生错误",
"errors": errors,
})
return
}
}
}
r.Use(errorHandlerMiddleware())
r.GET("/test", func(c *gin.Context) {
c.Error(errors.New("错误1"))
c.Error(errors.New("错误2"))
// 最终返回包含所有错误的统一响应
})
错误类型标记
Go
type CustomError struct {
Code int
Message string
}
func (e CustomError) Error() string {
return e.Message
}
func handler(c *gin.Context) {
err := CustomError{Code: 400, Message: "参数错误"}
c.Error(err).SetType(gin.ErrorTypePublic) // 设置错误类型
}
// 中间件中按类型处理
func typeAwareMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
c.Next()
publicErrors := c.Errors.ByType(gin.ErrorTypePublic)
privateErrors := c.Errors.ByType(gin.ErrorTypePrivate)
if len(publicErrors) > 0 {
c.JSON(400, gin.H{"errors": publicErrors.JSON()})
}
// private 错误只记录日志
for _, e := range privateErrors {
log.Printf("内部错误: %v", e)
}
}
}
错误类型常量
| 类型 | 说明 |
|---|---|
gin.ErrorTypePublic | 公开错误,返回给客户端 |
gin.ErrorTypePrivate | 私有错误,仅记录日志 |
gin.ErrorTypeAny | 所有错误 |
AbortWithStatusJSON 快捷处理
Go
func authMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
token := c.GetHeader("Authorization")
if token == "" {
c.AbortWithStatusJSON(401, gin.H{
"code": 401,
"message": "请先登录",
})
return
}
c.Next()
}
}
Panic 捕获处理
Go
func recoveryMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
defer func() {
if err := recover(); err != nil {
log.Printf("Panic: %v", err)
c.AbortWithStatusJSON(500, gin.H{
"code": 500,
"message": "服务器内部错误",
})
}
}()
c.Next()
}
}
业务错误统一处理
Go
// 定义业务错误结构
type BizError struct {
Code int
Message string
}
func (e *BizError) Error() string {
return e.Message
}
// 业务错误中间件
func bizErrorMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
c.Next()
// 检查是否有业务错误
for _, e := range c.Errors {
if bizErr, ok := e.Err.(*BizError); ok {
c.JSON(bizErr.Code, gin.H{
"code": bizErr.Code,
"message": bizErr.Message,
})
return
}
}
}
}
// 使用示例
r.Use(bizErrorMiddleware())
r.GET("/order/:id", func(c *gin.Context) {
order, err := getOrder(c.Param("id"))
if err != nil {
c.Error(&BizError{Code: 404, Message: "订单不存在"})
return
}
c.JSON(200, order)
})
错误处理最佳实践
Go
// 统一错误响应结构
type ErrorResponse struct {
Code int `json:"code"`
Message string `json:"message"`
Details []string `json:"details,omitempty"`
}
// 全局错误处理
func globalErrorHandler() gin.HandlerFunc {
return func(c *gin.Context) {
c.Next()
if c.IsAborted() {
return // 已处理,跳过
}
if len(c.Errors) > 0 {
details := c.Errors.JSON()
c.JSON(500, ErrorResponse{
Code: 500,
Message: "服务处理错误",
Details: details,
})
}
}
}
c.Error()不终止请求,适合收集多个错误统一处理;c.Abort()立即终止,适合认证失败等场景。
要点总结
c.Error()记录错误,请求继续执行c.Errors在中间件中统一处理所有错误- 使用
ErrorTypePublic/Private区分公开和私有错误 c.AbortWithStatusJSON()快捷终止并返回错误响应- Recovery 中间件捕获 panic 防止服务崩溃
📝 发现内容有误?点击此处直接编辑