golang http 恐慌的全局恢复处理程序

Posted

技术标签:

【中文标题】golang http 恐慌的全局恢复处理程序【英文标题】:global recover handler for golang http panic 【发布时间】:2015-04-29 00:26:53 【问题描述】:

我想创建全局错误处理程序以通过电子邮件发送。

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)

但是,如果我不知道哪里会发生错误,该怎么办?所以我应该添加一个全局recoverish 处理程序。但是具体怎么做我不知道。

更新

我在main 的开头添加了defer recover,但它在请求http://localhost:3001 时从未执行。所以恐慌不会通过电子邮件发送。

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")

【问题讨论】:

【参考方案1】:

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

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 handler 或negroni middleware 了解更多详情。

【讨论】:

e.Error() 应该是 err.Error()? 固定@eyeAppsLLC。 非常简洁的解决方案 r := recover() 从外部函数中隐藏 r *http.Request。如果您想在恢复块中访问它 - 最好更改名称,例如e := recover()【参考方案2】:

我相信这就是gorilla recovery handler 的用途

【讨论】:

以上是关于golang http 恐慌的全局恢复处理程序的主要内容,如果未能解决你的问题,请参考以下文章

golang Go Web Applications中的自定义处理程序和避免全局 - http://elithrar.github.io/article/custom-handlers-avoidi

golang Go Web Applications中的自定义处理程序和避免全局 - http://elithrar.github.io/article/custom-handlers-avoidi

golang 展示恐慌,推迟和恢复结合使用的完整例子

Golang恐慌崩溃预防

Go vs. 中的恐慌恢复try catch 用其他语言

在golang中输入正确但输出恐慌