请选择 进入手机版 | 继续访问电脑版

[Golang] Go应用中优雅处理Error的技巧总结

[复制链接]
查看206 | 回复36 | 2021-9-15 03:49:42 | 显示全部楼层 |阅读模式
目次

媒介

Go语言很强盛 并且如今 也非常 盛行 — 很多 项目都是用Go语言来实现的,如Kubernetes。Go语言的一个风趣 特性是它的多值返回功能提供了一种与其他编程语言不同的错误处理方法。 Go将error视为具有预定义范例 的值,其本身是一个interface范例 。然而,编写多层体系布局 应用程序并利用 api暴露应用的特性必要 有包含更多上下文信息的error处理,而不仅仅是一个值。 本文我们将探究 怎样 封装Go的error范例 以在应用程序中带来更大的价值。

用户自定义范例

我们将重写的Go里自带的error范例 ,起首 从一个自定义的错误范例 开始,该错误范例 将在程序中辨认 为error范例 。因此,我们引入一个封装了Go的 error的新自定义Error范例 。

  1. type GoError struct {
  2. error
  3. }
复制代码

上下文数据

当我们在Go中说error是一个值时,它是字符串值 - 任何实现了Error() string函数的范例 都可以视作error范例 。将字符串值视为error会使跨层的error处理复杂化,因此处理error字符串信息并不是精确 的方法。以是 我们可以把字符串和错误码解耦:

  1. type GoError struct {
  2. error
  3. Code string
  4. }
复制代码

如今 对error的处理将基于错误码Code字段而不是字符串。让我们通过上下文数据进一步对错误字符串举行 解耦,在上下文数据中可以利用 i18n包举行 国际化。

  1. type GoError struct {
  2. error
  3. Code string
  4. Data map[string]interface{}
  5. }
复制代码

Data包含用于构造错误字符串的上下文数据。错误字符串可以通过数据模板化:

  1. //i18N def
  2. "InvalidParamValue": "Invalid parameter value '{{.actual}}', expected '{{.expected}}' for '{{.name}}'"
复制代码

在i18N定义文件中,错误码Code将会映射到利用 Data构建的模板化的错误字符串中。

缘故因由 (Causes)

error大概 发生在任何一层,有必要为每一层提供处理error的选项,并在不丢失原始error值的环境 下进一步利用 附加的上下文信息对error举行 包装。GoError布局 体可以用Causes进一步封装,用来保存整个错误堆栈。

  1. type GoError struct {
  2. error
  3. Code string
  4. Data map[string]interface{}
  5. Causes []error
  6. }
复制代码

假如 必须保存多个error数据,则causes是一个数组范例 ,并将其设置为基本error范例 ,以便在程序中包含该缘故因由 的第三方错误。

组件(Component)

标记层组件将有助于辨认 error发生在哪一层,并且可以避免不必要的error wrap。比方 ,假如 service范例 的error组件发生在服务层,则大概 不必要 wrap error。检查组件信息将有助于防止暴露给用户不应该关照 的error,比如数据库error:

  1. type GoError struct {
  2. error
  3. Code string
  4. Data map[string]interface{}
  5. Causes []error
  6. Component ErrComponent
  7. }
  8. type ErrComponent string
  9. const (
  10. ErrService ErrComponent = "service"
  11. ErrRepo ErrComponent = "repository"
  12. ErrLib ErrComponent = "library"
  13. )
复制代码

相应 范例 (ResponseType)

添加一个错误相应 范例 如许 可以支持error分类,以便于相识 什么错误范例 。比方 ,可以根据相应 范例 (如NotFound)对error举行 分类,像DbRecordNotFound、ResourceNotFound、UserNotFound等等的error都可以归类为 NotFound error。这在多层应用程序开辟 过程中非常有用 ,而且是可选的封装:

  1. type GoError struct {
  2. error
  3. Code string
  4. Data map[string]interface{}
  5. Causes []error
  6. Component ErrComponent
  7. ResponseType ResponseErrType
  8. }
  9. type ResponseErrType string
  10. const (
  11. BadRequest ResponseErrType = "BadRequest"
  12. Forbidden ResponseErrType = "Forbidden"
  13. NotFound ResponseErrType = "NotFound"
  14. AlreadyExists ResponseErrType = "AlreadyExists"
  15. )
复制代码

重试

在少数环境 下,出现error会举行 重试。retry字段可以通过设置Retryable标记来决定是否要举行 error重试:

  1. type GoError struct {
  2. error
  3. Code string
  4. Message string
  5. Data map[string]interface{}
  6. Causes []error
  7. Component ErrComponent
  8. ResponseType ResponseErrType
  9. Retryable bool
  10. }
复制代码

GoError 接口

通过定义一个带有GoError实现的显式error接口,可以简化error检查:

  1. package goerr
  2. type Error interface {
  3. error
  4. Code() string
  5. Message() string
  6. Cause() error
  7. Causes() []error
  8. Data() map[string]interface{}
  9. String() string
  10. ResponseErrType() ResponseErrType
  11. SetResponseType(r ResponseErrType) Error
  12. Component() ErrComponent
  13. SetComponent(c ErrComponent) Error
  14. Retryable() bool
  15. SetRetryable() Error
  16. }
复制代码

抽象error

有了上述的封装方式,更紧张 的是对error举行 抽象,将这些封装保存在同一地方,并提供error函数的可重用性

  1. func ResourceNotFound(id, kind string, cause error) GoError {
  2. data := map[string]interface{}{"kind": kind, "id": id}
  3. return GoError{
  4. Code: "ResourceNotFound",
  5. Data: data,
  6. Causes: []error{cause},
  7. Component: ErrService,
  8. ResponseType: NotFound,
  9. Retryable: false,
  10. }
  11. }
复制代码

这个error函数抽象了ResourceNotFound这个error,开辟 者可以利用 这个函数来返回error对象而不是每次创建一个新的对象:

  1. //UserService
  2. user, err := u.repo.FindUser(ctx, userId)
  3. if err != nil {
  4. if err.ResponseType == NotFound {
  5. return ResourceNotFound(userUid, "User", err)
  6. }
  7. return err
  8. }
复制代码

结论

我们演示了怎样 利用 添加上下文数据的自定义Go的error范例 ,从而使得error在多层应用程序中更故意 义。你可以在这里[1]看到完备 的代码实现和定义。

到此这篇关于Go应用中优雅处理Error的文章就先容 到这了,更多相干 Go优雅处理Error内容请搜索 脚本之家从前 的文章或继续欣赏 下面的相干 文章渴望 大家以后多多支持脚本之家!

参考资料

[1] 这里: https://gist.github.com/prathabk/744367cbfc70435c56956f650612d64b


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
回复

使用道具 举报

avatar 兔仔妹致 | 2021-9-15 05:31:05 | 显示全部楼层
我裤子脱了,纸都准备好了,你就给我看这个?
回复

使用道具 举报

avatar 绣绣仙女酌 | 2021-9-15 20:19:44 | 显示全部楼层
勤奋灌水,天天向上!
回复

使用道具 举报

avatar 术数古籍专卖疤 | 2021-9-15 23:02:39 | 显示全部楼层
看帖不回帖的人就是耍流氓,我回复了!
回复

使用道具 举报

avatar 淡然一笑wwc | 2021-9-16 15:19:36 | 显示全部楼层
admin楼主的头像是本人吗?
回复

使用道具 举报

avatar Megatron832 | 2021-9-24 01:29:53 | 显示全部楼层
admin楼主人气很旺!
回复

使用道具 举报

avatar 聚雅阁砚堂 | 2021-9-26 23:00:23 | 显示全部楼层
admin楼主英明!
回复

使用道具 举报

avatar 护身马甲上阵兜 | 2021-9-28 14:26:02 | 显示全部楼层
这个帖子会火的,鉴定完毕!
回复

使用道具 举报

avatar 枫夜渔火火f | 2021-9-29 10:12:47 | 显示全部楼层
我只是来赚积分的!
回复

使用道具 举报

avatar 群主713 | 2021-9-29 10:15:23 | 显示全部楼层
楼上的忘记吃药了!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则