我想创建全局错误处理程序,通过邮箱发送.

package main

import (
    "github.com/gorilla/mux"
    "log"
    "net/http"
)

func main() {
    rtr := mux.NewRouter()
    rtr.HandleFunc("/", withPanic).Methods("GET")

    http.Handle("/", rtr)
    log.Println("Listening...")

    http.ListenAndServe(":3001", http.DefaultServeMux)
}

func withPanic(w http.ResponseWriter, r *http.Request) {
    panic("somewhere here will be panic, but I don't know where exactly")
}

如何使其全球化.如果我知道错误会发生在哪里,那就很容易了

if err != nil {
sendMeMail(err)
}

但是,当我不知道错误将在哪里发生时,该怎么办呢?所以我应该添加一个全局recover左右的处理程序.但具体怎么做我不知道.

Update

我将defer recover加到main的开头,但它从未在请求http://localhost:3001时执行.所以panic 不会通过邮箱发送.

package main

import (
    "errors"
    "fmt"
    "github.com/gorilla/mux"
    "log"
    "net/http"
)

func main() {
    defer func() {
        if r := recover(); r != nil {
            fmt.Println("Recovered in f", r)
            // find out exactly what the error was and set err
            var err error
            switch x := r.(type) {
            case string:
                err = errors.New(x)
            case error:
                err = x
            default:
                err = errors.New("Unknown panic")
            }
            if err != nil {
                // sendMeMail(err)
                fmt.Println("sendMeMail")
            }
        }
    }()
    rtr := mux.NewRouter()
    rtr.HandleFunc("/", withPanic).Methods("GET")

    http.Handle("/", rtr)
    log.Println("Listening...")

    http.ListenAndServe(":3001", http.DefaultServeMux)
}

func withPanic(w http.ResponseWriter, r *http.Request) {
    panic("somewhere here will be panic, but I don't know where exactly")
}

推荐答案

您可以将处理程序包装在恢复中间件中

package main

import (
    "errors"
    "github.com/gorilla/mux"
    "log"
    "net/http"
)

func main() {
    m := mux.NewRouter()
    m.Handle("/", RecoverWrap(http.HandlerFunc(handler))).Methods("GET")

    http.Handle("/", m)
    log.Println("Listening...")

    http.ListenAndServe(":3001", nil)

}

func handler(w http.ResponseWriter, r *http.Request) {
    panic(errors.New("panicing from error"))
}

func RecoverWrap(h http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        defer func() {
            r := recover()
            if r != nil {
                var err error
                switch t := r.(type) {
                case string:
                    err = errors.New(t)
                case error:
                    err = t
                default:
                    err = errors.New("Unknown error")
                }
                sendMeMail(err)
                http.Error(w, err.Error(), http.StatusInternalServerError)
            }
        }()
        h.ServeHTTP(w, r)
    })
}

func sendMeMail(err error) {
    // send mail
}

您可以查看codahale recovery handlernegroni middleware了解更多详细信息.

Go相关问答推荐

正确使用pgtype的方法

如何模拟go的Elastic search SDK?

Golang:访问any类型泛型上的字段

使用Cookie身份验证的Gorilla Golang Websocket优化

是否可以在 hyperledger-chaincode 中使用 gRPC?如果可以,我如何避免在测试网络上调用时出错?

最长连续重复的字符golang

如何在 Golang 中打印 2 列表?

如何使用泛型将接口转换为指定类型

我在 go 中制作的递归函数有什么问题?

Gorm 预加载给出了模糊的列错误

具有两个或多个模型的 GORM 查询

GRPC 元数据未在 Go 中更新

Golang泛型在用作 map 元素时不起作用

try 与 golang testify/suite 并行运行测试失败

函数调用中的类型参数panic

具有相同提前返回语句的函数的不同基准测试结果

Go 加密库创建的 PKCS1 公钥与openssl rsa ...之间的区别

使用 delve 在容器中调试 Golang:container_linux.go:380:启动容器进程导致:exec:/dlv:stat /dlv:没有这样的文件或目录

如何动态解析 Go Fiber 中的请求正文?

GORM 不忽略带有 `gorm:"-"` 的字段