为了账号安全,请及时绑定邮箱和手机立即绑定

错误处理 anon 函数的最佳做法

错误处理 anon 函数的最佳做法

Go
翻过高山走不出你 2022-08-01 17:22:28
我正在处理一些大型Go项目,但我想问一个关于错误处理最佳实践的问题。据我所知,错误不应该被隐藏/“捕获”,但我可能是错的。在我正在研究的许多项目中,我在http处理程序中看到了很多这样的情况。有时大约有 8 个函数调用func FooHandler(w http.ResponseWriter, r *http.Request) {    if err := func() error {        var1, err := doSomething1()        if err != nil {             return fmt.Error("some error")        }        var2, err := doSomething2()        if err != nil {             return fmt.Error("some error")        }        var3, err := doSomething3()        if err != nil {             return fmt.Error("some error")        }        var4, err := doSomething4()        if err != nil {             return fmt.Error("some error")        }    }(); err != nil {        // build error response here    }    // do successful response here}这似乎就像在围棋中做尝试/捕捉,但最好知道这是否被接受的做法。另一种方法是使用函数来编写错误响应,但会重复代码。if err != nil
查看完整描述

1 回答

?
蓝山帝景

TA贡献1843条经验 获得超7个赞

上述方法完全没问题,不会像其他语言那样“捕捉”任何东西。try .. catch


匿名函数的主要原因是只编写一次特定于错误的响应。如果您不喜欢这种方法,还有其他方法可以做到这一点。


句柄错误函数

例如,您可以有一个函数来处理/返回错误,以便此代码不会使处理程序混乱:


func handleErr(w http.ResponseWriter, err error, statusCode int) {

    log.Printf("statusCode: %d; error: %s", statusCode, err)


    w.WriteHeader(statusCode)


    bts, err := json.Marshal(struct {

        Error string

    }{

        Error: err.Error(),

    })

    if err != nil {

        _, _ = w.Write([]byte(`{"Error":"error while marshalling error response"`))

    }


    _, _ = w.Write(bts)

}

然后,处理程序将如下所示:


func FooHandler(w http.ResponseWriter, r *http.Request) {

    var1, err := doSomething1()

    if err != nil {

        handleErr(w, err, http.StatusBadRequest, "some user error msg")

        return

    }


    var2, err := doSomething2()

    if err != nil {

        handleErr(w, err, http.StatusUnauthorized, "some user error msg")

        return

    }


    var3, err := doSomething3()

    if err != nil {

        handleErr(w, err, http.StatusInternalServerError, "some user error msg")

        return

    }


    var4, err := doSomething4()

    if err != nil {

        handleErr(w, err, http.StatusInternalServerError, "some user error msg")

        return

    }


    // do successful response here

}

使用中间件

正如注释中@mkopriva建议的那样,您还可以对处理程序使用包装器:


func handleErr(f func(w http.ResponseWriter, r *http.Request) (int, error)) http.HandlerFunc {

    return func(w http.ResponseWriter, r *http.Request) {

        statusCode, err := f(w, r)

        if err != nil {

            return

        }


        log.Printf("statusCode: %d; error: %s", statusCode, err)


        w.WriteHeader(statusCode)


        bts, err := json.Marshal(struct {

            Error string

        }{

            Error: err.Error(),

        })

        if err != nil {

            _, _ = w.Write([]byte(`{"Error":"error while marshalling error response"`))

        }


        _, _ = w.Write(bts)

    }

}

注册处理程序时,它将被包装:


http.Handle("/foo", handleErr(FooHandler))

现在可以返回状态代码和错误:FooHandler


func FooHandler(w http.ResponseWriter, r *http.Request) (int, error) {

    var1, err := doSomething1()

    if err != nil {

        return http.StatusBadRequest, fmt.Error("some error")

    }


    var2, err := doSomething2()

    if err != nil {

        return http.StatusUnauthorized, fmt.Error("some error")

    }


    var3, err := doSomething3()

    if err != nil {

        return http.StatusInternalServerError, fmt.Error("some error")

    }


    var4, err := doSomething4()

    if err != nil {

        return http.StatusInternalServerError, fmt.Error("some error")

    }


    // do successful response here

    return http.StatusOK, nil

}


查看完整回答
反对 回复 2022-08-01
  • 1 回答
  • 0 关注
  • 84 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信