【问题标题】:Better error handling更好的错误处理
【发布时间】:2018-01-12 11:01:44
【问题描述】:

这里https://github.com/astaxie/build-web-application-with-golang/blob/master/en/11.1.md 描述了如何根据http 包使用自定义路由器和自定义错误类型来增强错误处理。

type appError struct {
    Error   error
    Message string
    Code    int
}    

type appHandler func(http.ResponseWriter, *http.Request) *appError
// custom handler catching errors
func (fn appHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    if e := fn(w, r); e != nil { // e is *appError, not os.Error.
        c := appengine.NewContext(r)
        c.Errorf("%v", e.Error)
        http.Error(w, e.Message, e.Code)
    }
}
// fetch data or return *appError
func viewRecord(w http.ResponseWriter, r *http.Request) *appError {
    c := appengine.NewContext(r)
    key := datastore.NewKey(c, "Record", r.FormValue("id"), 0, nil)
    record := new(Record)
    if err := datastore.Get(c, key, record); err != nil {
        return &appError{err, "Record not found", 404}
    }
    if err := viewTemplate.Execute(w, record); err != nil {
        return &appError{err, "Can't display record", 500}
    }
    return nil
}

目的是让所有的handler在出错时返回*appError并写入到路由器的response中,所以不需要在viewRecord的代码中直接调用c.JSON(500, err) .

如何对Gin做同样的事情?

【问题讨论】:

标签: http go web-applications error-handling


【解决方案1】:

Here@manucorporat gin-developer 说:

我们鼓励开发人员使用中间件来处理错误响应,这样他们就可以将错误逻辑与正常的流程逻辑分开。

在 Gin 中实现集中错误处理,您应该使用 .Use(Middleware) 并在路径处理程序的代码中使用 gin.Context.Error() 将错误信息附加到请求上下文。中间件知道 gin.Context.Errors,您可以在此处阅读它们并在 gin.Context.Next() 之后按照您的意愿处理。

下面的代码。

错误处理 Gin 中间件:

//
// APP error definition
//
type appError struct {
    Code     int    `json:"code"`
    Message  string `json:"message"`
}

//
// Middleware Error Handler in server package
//
func JSONAppErrorReporter() gin.HandlerFunc {
    return jsonAppErrorReporterT(gin.ErrorTypeAny)
}

func jsonAppErrorReporterT(errType gin.ErrorType) gin.HandlerFunc {
    return func(c *gin.Context) {
        c.Next()
        detectedErrors := c.Errors.ByType(errType)

        log.Println("Handle APP error")
        if len(detectedErrors) > 0 {
            err := detectedErrors[0].Err
            var parsedError *appError
            switch err.(type) {
            case *appError:
                parsedError = err.(*appError )
            default:
                parsedError = &appError{ 
                  code: http.StatusInternalServerError,
                  message: "Internal Server Error"
                }
            }
            // Put the error into response
            c.IndentedJSON(parsedError.Code, parsedError)
            c.Abort()
            // or c.AbortWithStatusJSON(parsedError.Code, parsedError)
            return
        }

    }
}

//
//  Report Error in app
//
func fetchSingleHostGroup(c *gin.Context) {
    hostgroupID := c.Param("id")

    hostGroupRes, err := getHostGroupResource(hostgroupID)

    if err != nil {
        // put the Error to gin.Context.Errors
        c.Error(err)
        return
    }
    // return data of OK
    c.JSON(http.StatusOK, *hostGroupRes)
}
//
// Server setup
//
func main() {
    router := gin.Default()
    router.Use(JSONAppErrorReporter())
    router.GET("/hostgroups/:id", fetchSingleHostGroup)
    router.Run(":3000")
}

另一种错误处理思路可以参考:

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2012-01-10
  • 1970-01-01
  • 2018-10-26
  • 2020-11-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-14
相关资源
最近更新 更多