错误处理中间件会引发运行时错误

时间:2018-12-20 00:55:55

标签: go

我有一段错误处理中间件:

func Error(next http.HandlerFunc) http.Handler {

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

        defer func() {
            if err := recover(); err != nil {

                log.Error("Caught error in defer/recover middleware: ", err)
                originalError := err.(struct{ OriginalError error }).OriginalError

                if originalError != nil {
                    log.Error("Original error in defer/recover middleware: ", originalError)
                }

                statusCode := err.(struct{ StatusCode int }).StatusCode

                if statusCode != 0 {
                    w.WriteHeader(statusCode)
                } else {
                    w.WriteHeader(http.StatusInternalServerError)
                }

                message := err.(struct{ Message string }).Message

                if message == "" {
                    message = "Unknown error message."
                }

                json.NewEncoder(w).Encode(struct {
                    ID string
                }{
                    message,
                })
            }
        }()
        next.ServeHTTP(w, r)
    })

}

由于它已被推迟,因此每个请求将至少运行一次,而我得到此错误:

ERRO[0009] Caught error in defer/recover middleware: runtime error: index out of range 
2018/12/19 16:53:47 http: panic serving 127.0.0.1:50394: interface conversion: interface {} is runtime.errorString, not struct { OriginalError error }
goroutine 34 [running]:
net/http.(*conn).serve.func1(0xc420224000)
        /usr/lib/go-1.10/src/net/http/server.go:1726 +0xd0
panic(0x700300, 0xc420232340)
        /usr/lib/go-1.10/src/runtime/panic.go:502 +0x229
huru/mw.Error.func1.1(0x7a5b60, 0xc420244000)
        /home/oleg/codes/huru/api/src/huru/mw/middleware.go:113 +0x309
panic(0x6fd380, 0x919c10)
        /usr/lib/go-1.10/src/runtime/panic.go:502 +0x229
huru/mw.Auth.func1(0x7a5b60, 0xc420244000, 0xc42023a200)
        /home/oleg/codes/huru/api/src/huru/mw/middleware.go:53 +0x4ae
net/http.HandlerFunc.ServeHTTP(0xc4201133c0, 0x7a5b60, 0xc420244000, 0xc42023a200)
        /usr/lib/go-1.10/src/net/http/server.go:1947 +0x44
huru/mw.Logging.func1(0x7a5b60, 0xc420244000, 0xc42023a200)
        /home/oleg/codes/huru/api/src/huru/mw/middleware.go:21 +0xcb
net/http.HandlerFunc.ServeHTTP(0xc4200117c0, 0x7a5b60, 0xc420244000, 0xc42023a200)
        /usr/lib/go-1.10/src/net/http/server.go:1947 +0x44
huru/mw.Error.func1(0x7a5b60, 0xc420244000, 0xc42023a200)
        /home/oleg/codes/huru/api/src/huru/mw/middleware.go:140 +0x86
net/http.HandlerFunc.ServeHTTP(0xc4200117d0, 0x7a5b60, 0xc420244000, 0xc42023a200)
        /usr/lib/go-1.10/src/net/http/server.go:1947 +0x44
github.com/gorilla/mux.(*Router).ServeHTTP(0xc42013e000, 0x7a5b60, 0xc420244000, 0xc42023a200)
        /home/oleg/codes/huru/api/src/github.com/gorilla/mux/mux.go:162 +0xed
net/http.serverHandler.ServeHTTP(0xc4200a5110, 0x7a5b60, 0xc420244000, 0xc42023a000)
        /usr/lib/go-1.10/src/net/http/server.go:2697 +0xbc

我不知道如何解决它。

1 个答案:

答案 0 :(得分:2)

从错误消息中,err对象类型是runtime.errorString而不是struct { OriginalError error }。强制type assertion会引起恐慌。

我认为最好在类型断言期间使用第二个返回值,以检查转换过程是否成功。

if err := recover(); err != nil {

    if temp, ok := err.(struct{ OriginalError error }); ok {
        log.Error("Caught error in defer/recover middleware: ", err)
        originalError := temp.OriginalError

        if originalError != nil {
            log.Error("Original error in defer/recover middleware: ", originalError)
        }
    }

    if temp, ok := err.(struct{ StatusCode int }); ok {
        statusCode := temp.StatusCode

        if statusCode != 0 {
            w.WriteHeader(statusCode)
        } else {
            w.WriteHeader(http.StatusInternalServerError)
        }
    }

    if temp, ok := err.(struct{ Message string }); ok {
        message := temp.Message

        if message == "" {
            message = "Unknown error message."
        }

        json.NewEncoder(w).Encode(struct {
            ID string
        }{
            message,
        })
    }
}