【问题标题】:Working with errors in Go在 Go 中处理错误
【发布时间】:2016-11-15 14:15:50
【问题描述】:

我已经使用 Go 有一段时间了,但还没有真正确定我是如何处理错误的。

即使是标准库也有许多不同的方法来处理错误(有些甚至无法在不求助于字符串匹配的情况下检查错误)。

我最近阅读了 Dave Cheney 的博文 Inspecting Errors。这听起来像是朝着正确方向迈出的一步,但我仍然很难真正投入使用。

假设我已经制作了一个包a,它向第 3 方 REST API(例如 Facebook Graph)发出请求。我希望这个包能够公开与 API 匹配的函数 - 比如说GetUser。

致电GetUser 会产生多种结果:

  1. 成功
  2. 由于请求失败(例如 3rd 方 API 关闭)而失败
  3. 第 3 方 API 返回错误(如未找到用户)
  4. 响应或类似的反序列化失败

断言行为错误在第二种情况下非常有效。但是它在区分第三种和第四种情况方面存在不足。

我当前的用例是实现我自己的使用第一个包的 REST API。在这种情况下,我希望能够分别返回200 OK、503 Service Unavailable、400 Bad Request、500 Internal Server Error 对可能结果的响应。

在不必包含从包a 返回http 响应代码或类似代码的情况下,解决此问题的通用方法是什么?

【问题讨论】:

标签: go error-handling


【解决方案1】:

我要做的是定义一些“包装错误”来表示错误实际发生在哪里。例如

type SerializationError struct { Error error }
func (err SerializationError) Error() string { return err.Error.Error() }

type HTTPError struct { Error error }
// ...

然后在您的 API 客户端的代码中:

b, err := json.Marshal(v)
if err != nil {
     return nil, SerializationError{err}
}

// ...

resp, err := client.Post(url, ct, body)
if err != nil {
    return nil, HTTPError{err}
}

然后,您可以这样做:

err := client.GetUser(id)
switch err.(type) {
case SerializationError:
    // respond with 400
case HTTPError:
    // respond with 500
// etc.
}

【讨论】:

  • Dave Cheneys 博客的重点是应该避免类型断言错误。当所有不同的可能错误都需要自己的类型时,它也会迅速增加,因此调用者可以判断如何在链上进一步处理错误。
【解决方案2】:

在处理了一段时间后,没有更接近一个感觉恰到好处的解决方案,我开始接受没有一个好的单一解决方案。

我猜这也可能是Dave Cheney 的意思:

但是,我得出的结论是,没有单一的方法可以处理错误。

由于我仍然想避免由于带来的依赖挑战而对错误进行类型断言,因此我最终引入了类似于链接文章中提到的Temporary() bool 模式的Internal() bool 行为。

这至少允许我断言行为,而不必强制导入最初创建错误的包。

这不是最合适的,但现在必须这样做。

Ainar-G 的 answer 也值得一看。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-11-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多