在Web应用程序中使用恐慌

vbe*_*nar 4 error-handling web-applications 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})
    }
}
Run Code Online (Sandbox Code Playgroud)

在我的实际代码中

result, err := SomeApi(...)
PanicIf(err, http.StatusInternalServerError, "SomeApi")
Run Code Online (Sandbox Code Playgroud)

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

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

Von*_*onC 10

有什么我想念的,所以这种方法不会有效吗?

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

与三十年前一样,C++异常仍然像安全一样难以安全使用.当你的调用堆栈的任何部分可以在没有警告的情况下爆炸时,难怪有这么多的C++商店强制要求不使用异常.

它指的是" 为什么Go得到正常的例外 "(2012年,在Go1.0之前,但今天仍然有效):

Go确实有一个叫做的设施panic,如果你足够眯眼,你可能会想到恐慌和扔一样,但你错了.
当你抛出和异常时,你就会成为调用者的问题

throw new SomeoneElsesProblem();
Run Code Online (Sandbox Code Playgroud)

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

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

panic("inconceivable")
Run Code Online (Sandbox Code Playgroud)

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

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


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

话虽这么说,文章" 延迟,恐慌和恢复 "确实提到了恐慌(json,(d *decodeState) unmarshal方法)的真实案例,并添加:

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

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