在Web应用程序中使用恐慌

时间:2014-11-04 13:56:37

标签: web-applications error-handling go

我正在使用Go编写我的Web应用程序。我想将大多数错误从API转换为恐慌,然后在更高级别的函数中捕获这些恐慌,记录它们并将错误页面返回给用户。

这样的事情:

func Handler(body func(http.ResponseWriter, *http.Request)) func(http.ResponseWriter, *http.Request) {
    return func(responseWriter http.ResponseWriter, request *http.Request) {
        defer recoverIfPanic(responseWriter, request)
        body(responseWriter, request)
    }
}

func recoverIfPanic(responseWriter http.ResponseWriter, request *http.Request) {
    reason := recover()
    if reason == nil {
        return
    }
    // log and return http error
}

func PanicIf(err error, httpStatus int, description string) {
    if error != nil {
        panic(MyPanicStruct{err: err, httpStatus: httpStatus, description: description})
    }
}

和我的实际代码

result, err := SomeApi(...)
PanicIf(err, http.StatusInternalServerError, "SomeApi")

在99%的情况下,我无法做出任何合理的事情,例如: SQL Server返回意外错误或文件系统中缺少文件,我想要的只是记录这种情况并将错误返回给用户。所以我看不出任何理由我应该回来#34;错误"手动展开堆栈,实际上我丢失了堆栈跟踪和上下文,找到错误原因会更加困难。

我有什么想念,所以这种方法不能很好地运作吗?似乎大多数Go文章建议不要使用恐慌/恢复,但我不明白为什么。它看起来与Java(和类似语言)中的旧的throw-catch机制完全相同,并且它非常适合Web应用程序。

2 个答案:

答案 0 :(得分:10)

  

我有什么想念,所以这种方法不能很好地运作吗?

今天(!)2014年11月4日由Dave Cheney在" Error handling vs. exceptions redux"

中讨论
  

C ++异常,仍然像三十年前一样安全使用。当你的调用堆栈的任何部分在没有警告的情况下爆炸时,难怪很多C ++商店要求不使用例外。

它指的是" Why Go gets exceptions right" (2012年,在Go1.0之前,但今天仍然有效):

  

Go确实有一个名为panic的设施,如果你足够眯眼,你可能会想到恐慌与投掷相同,但你错了。
  当你抛出和异常时,你就是调用者的问题

throw new SomeoneElsesProblem();
  

例如,在C ++中,如果无法从enum转换为string等效项,或者在从字符串解析日期时使用Java,则可能会抛出异常。
  在互联网连接的世界中,网络中的每个输入都必须被认为是敌对的,是不是将字符串解析成日期非常特殊?当然不是。

     

当你在Go中恐慌时,你会吓坏,这不是别人的问题,而是游戏胜过男人。

panic("inconceivable")
  

panic对你的程序来说总是致命的   在panicing中你永远不会认为你的来电者可以解决问题。因此,恐慌仅用于特殊情况,代码无法使用,或者任何集成代码的人都可以继续使用。

     

不在Go中包含例外的决定是其简单性和正交性的一个例子。使用多个返回值和一个简单的约定,Go解决了让程序员知道什么时候出错的问题,并为真正特殊的事情保留恐慌。


使用err的其他方法将在官方维基页面" Error handling and Go"中讨论。

话虽如此,文章" Defer, Panic, and Recover"确实提到恐慌的真实案例(json package(d *decodeState) unmarshal method),并添加:

  

Go库中的约定是即使当包在内部使用panic时,其外部API仍会显示明确的错误返回值

因此,如果您使用恐慌严格来说是内部恐慌,那就可以了。

答案 1 :(得分:2)

所以我个人的观点是,恐慌是魔鬼的工作,几乎永远不会被使用。

说过我把所有的http处理程序包装成恐慌恢复,因为有许多事情(包括stdlib)恐慌并且你必须处理它 - 取消你的网络服务器不是一个正确的回应 - 同意。

我们已经完成的工作是使用我们自己的错误包覆盖我们的错误包,因此当我们生成错误时,错误本身和回溯会被拍摄到某个站点,因此您可以在那里记录/跟踪它。

例如原生的http实现 - > https://deferpanic.com/help/exception-handling/native

我相信这种方法可以让你吃蛋糕而且不吃恐慌/恢复。