我正在使用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应用程序。
答案 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
我相信这种方法可以让你吃蛋糕而且不吃恐慌/恢复。