Eswlnk Blog Eswlnk Blog
  • 资源
    • 精彩视频
    • 破解专区
      • WHMCS
      • WordPress主题
      • WordPress插件
    • 其他分享
    • 极惠VPS
    • PDF资源
  • 关于我
    • 论文阅读
    • 关于本站
    • 通知
    • 左邻右舍
    • 玩物志趣
    • 日志
    • 专题
  • 热议话题
    • 游戏资讯
  • 红黑
    • 渗透分析
    • 攻防对抗
    • 代码发布
  • 自主研发
    • 知识库
    • 插件
      • ToolBox
      • HotSpot AI 热点创作
    • 区块
    • 快乐屋
    • 卡密
  • 乱步
    • 文章榜单
    • 热门标签
  • 问答中心反馈
  • 注册
  • 登录
首页 › 代码发布 › Go语言错误处理为什么更推荐使用pkg/errors 三方库?

Go语言错误处理为什么更推荐使用pkg/errors 三方库?

Eswlnk的头像
Eswlnk
2022-06-27 13:39:45
Go语言错误处理为什么更推荐使用pkg/errors 三方库?-Eswlnk Blog
智能摘要 AI
在Go语言项目开发中,使用标准库`errors`进行错误处理存在局限性,特别是在分层设计(如MVC或Clean Architecture)项目中,容易出现错误覆盖问题。标准库`errors.New`只能定义简单错误信息,导致不同层级的错误信息相互覆盖,难以追踪和调试。 为解决此问题,文章推荐使用三方库`github.com/pkg/errors`。该库不仅能保留标准库的功能,还能附加错误堆栈信息,便于追踪错误来源。通过`Wrap`方法,可以在已有错误基础上附加新信息,避免覆盖。此外,`WithMessage`和`WithStack`方法提供了更灵活的错误处理方式。 总结来看,使用`pkg/errors`能有效改善Go项目中的错误处理流程,提升代码可读性和维护性。

Go 语言项目开发中,我们通常需要在代码逻辑中进行错误处理,Go 官方标准库 errors 为我们提供了一些方法,比如 New,Unwarp,Is 和 As。

其中,我们用的最多的是 New,但是,在我们实际 Go 项目开发中,会使用一些分层设计,比如 MVC,Clean Architecture 等。

在使用分层设计的项目中,如果我们使用 Go 标准库 errors 定义错误,就会遇到错误覆盖的问题。

Go语言错误处理为什么更推荐使用pkg/errors 三方库?-Eswlnk Blog

关于标准库 errors 的错误覆盖问题

Go标准库 errors 的 New 方法,只能定义一条简单的错误信息,在分层设计的项目代码中,就会遇到错误覆盖的问题,比如我们本文的示例项目代码,使用的是 Clean Architecture 分层设计。

项目分层目录:

.
├── app
│   └── main.go
├── domain
│   └── user.go
├── go.mod
├── go.sum
└── user
    ├── delivery
    │   └── http
    │       └── user.go
    ├── repository
    │   └── mysql
    │       └── user.go
    └── usecase
        └── user.go

在示例项目中,我们先使用 Go 标准库 errors 的 New 方法定义错误,代码片段如下:

repository 层:

func (m *mysqlUserRepository) GetUserById(ctx context.Context, user *domain.User) (err error) {
 _, err = m.DB.Get(user)
 fmt.Printf("mysqlUserRepository || GetUserById() || uid=%v || err=%v\n", user.Id, err)
 return
}

usecase 层:

func (u *userUsecase) GetUserById(ctx context.Context, user *domain.User) (err error) {
 if user.Id == 0 {
  err = errors.New("invalid request parameter")
 }
 err = u.userRepo.GetUserById(ctx, user)
 fmt.Printf("userUsecase || GetUserById() || uid=%v || err=%v\n", user.Id, err)
 return
}

delivery 层:

func (u *UserHandler) GetUserById(c echo.Context) error {
 idP, err := strconv.Atoi(c.Param("id"))
 if err != nil {
  return c.JSON(http.StatusNotFound, err)
 }
 id := int64(idP)
 ctx := c.Request().Context()
 user := &domain.User{
  Id: id,
 }
 err = u.UserUsecase.GetUserById(ctx, user)
 if err != nil {
  err = errors.New("UserUsecase error")
  fmt.Printf("UserHandler || GetUserById() || uid=%v || err=%+v\n", id, err)
  return c.JSON(http.StatusInternalServerError, err)
 }
 return c.JSON(http.StatusOK, user)
}

阅读上面三段代码,我们可以发现,我们在每层中都有错误处理的代码,我们故意使用错误的请求参数,并将数据库连接的密码写错,触发应用程序的错误。

输出结果:

mysqlUserRepository || GetUserById() || uid=1 || err=Error 1045: Access denied for user 'root'@'172.17.0.1' (using password: YES)
userUsecase || GetUserById() || uid=1 || err=Error 1045: Access denied for user 'root'@'172.17.0.1' (using password: YES)
UserHandler || GetUserById() || uid=1 || err=UserUsecase error

阅读输出结果,我们可以发现,usecase 层定义的错误,被调用的 repository 层返回错误覆盖;delivery 层定义的错误将 usecase 层返回的错误覆盖。

Go语言错误处理为什么更推荐使用pkg/errors 三方库?-Eswlnk Blog

因为我们在每层都打印了错误,仔细排查,还是可以定位到错误,但是还是比较繁琐,不仅每层打印错误使代码不够优雅,而且也不能快速定位到错误。

怎么解决这个问题呢?使用三方库 github.com/pkg/errors 替换 Go 标准库 errors。

三方库 pkg/errors

使用三方库 pkg/errors 可以解决在分层设计的项目中调用堆栈的错误信息互相覆盖,可以为我们输出错误的堆栈信息,可以在已有错误信息的基础上附加新的错误信息,从而解决输出的错误信息缺失上下文的问题。

我们修改一下 Part 02 的示例代码,将 Go 标准库 errors 替换为三方库 pkg/errors,相信细心的读者朋友们已经发现,因为这两个包的名字相同,而且都有 New 方法,所以替换起来也比较方便,只需替换导入的包。

Go语言错误处理为什么更推荐使用pkg/errors 三方库?-Eswlnk Blog

示例代码:

import (
 // "errors"
 "fmt"
 "github.com/labstack/echo/v4"
 "github.com/pkg/errors"
 "github.com/weirubo/learn_go/lesson41/domain"
 "net/http"
 "strconv"
)

替换后的输出结果:

mysqlUserRepository || GetUserById() || uid=0 || err=Error 1045: Access denied for user 'root'@'172.17.0.1' (using password: YES)
userUsecase || GetUserById() || uid=0 || err=Error 1045: Access denied for user 'root'@'172.17.0.1' (using password: YES)
UserHandler || GetUserById() || uid=0 || err=UserUsecase error
github.com/weirubo/learn_go/lesson41/user/delivery/http.(*UserHandler).GetUserById
        /Users/frank/GolandProjects/learn_go/lesson41/user/delivery/http/user.go:36
github.com/labstack/echo/v4.(*Echo).add.func1
        /Users/frank/go/pkg/mod/github.com/labstack/echo/v4@v4.7.2/echo.go:520
github.com/labstack/echo/v4.(*Echo).ServeHTTP
        /Users/frank/go/pkg/mod/github.com/labstack/echo/v4@v4.7.2/echo.go:630
net/http.serverHandler.ServeHTTP
        /usr/local/go/src/net/http/server.go:2916
net/http.(*conn).serve
        /usr/local/go/src/net/http/server.go:1966
runtime.goexit
        /usr/local/go/src/runtime/asm_amd64.s:1571

阅读上面的输出结果,我们可以发现错误处理包由 Go 标准库 errors 替换为三方库 pkg/errors 后,输出结果不仅有 Go 标准库 errors 的错误信息,还输出了错误的堆栈信息。

目前为止,我们只是切换了一下导入的包,错误信息就包含了错误的堆栈信息,但是,我们的错误覆盖问题还没有得到解决,我们还需要使用三方库 pkg/errors 的 Wrap 方法,我们再修改一下代码,将 New 方法替换为 Wrap 方法。

delivery 层:

...
if err != nil {
  // err = errors.New("UserUsecase error")
  err = errors.Wrap(err, "UserUsecase error")
  fmt.Printf("UserHandler || GetUserById() || uid=%v || err=%+v\n", id, err)
  return c.JSON(http.StatusInternalServerError, err)
 }
...

阅读上面这段代码,我们修改 delivery 层的错误处理代码,将 New 方法替换为 Wrap 方法,它可以在已有错误信息的基础上,附加新的错误信息和错误的堆栈信息。

输出结果:

mysqlUserRepository || GetUserById() || uid=0 || err=Error 1045: Access denied for user 'root'@'172.17.0.1' (using password: YES)
userUsecase || GetUserById() || uid=0 || err=Error 1045: Access denied for user 'root'@'172.17.0.1' (using password: YES)
UserHandler || GetUserById() || uid=0 || err=Error 1045: Access denied for user 'root'@'172.17.0.1' (using password: YES)
UserUsecase error
github.com/weirubo/learn_go/lesson41/user/delivery/http.(*UserHandler).GetUserById
        /Users/frank/GolandProjects/learn_go/lesson41/user/delivery/http/user.go:37
github.com/labstack/echo/v4.(*Echo).add.func1
        /Users/frank/go/pkg/mod/github.com/labstack/echo/v4@v4.7.2/echo.go:520
github.com/labstack/echo/v4.(*Echo).ServeHTTP
        /Users/frank/go/pkg/mod/github.com/labstack/echo/v4@v4.7.2/echo.go:630
net/http.serverHandler.ServeHTTP
        /usr/local/go/src/net/http/server.go:2916
net/http.(*conn).serve
        /usr/local/go/src/net/http/server.go:1966
runtime.goexit
        /usr/local/go/src/runtime/asm_amd64.s:1571

阅读以上输出结果,我们可以发现在 delivery 层定义的错误信息,没有再覆盖调用 usecase 层方法返回的错误信息,二者都被正常输出。

需要注意的是,同时输出错误信息和堆栈信息,占位符需要使用 %+v,也不要在每层都输出堆栈信息,这样会重复打印堆栈信息,通常做法是如果下层打印了堆栈信息,上层就不要再打印堆栈信息。

此外,三方库 pkg/errors 的另外两个方法 WithMessage 和 WithStack 也比较常用,它们分别是在已有的错误信息的基础上,附加新的错误信息和错误的堆栈信息,我们在实际项目开发中,可以按需选择使用合适的方法。

Go语言错误处理为什么更推荐使用pkg/errors 三方库?-Eswlnk Blog

总结

本文我们讲述了使用 Go 标准库 errors 进行错误处理的局限性和不足,为了解决它的不足,我们介绍了使用三方库 pkg/errors 替换 Go 标准库 errors,和三方库 pkg/errors 的几个常用方法的使用方式。

关于三方库 pkg/errors 的更多方法,感兴趣的读者朋友们可以阅读文档了解如何使用。

本站默认网盘访问密码:1166
本站默认网盘访问密码:1166
echogo语言go语言适合做什么go语言错误处理为什么那么奇怪pkg文件怎么安装
0
0
Eswlnk的头像
Eswlnk
一个有点倒霉的研究牲站长
赞赏
JAVA如何自定义Mysql连接池
上一篇
趣谈被高估的DRY编程原则
下一篇

评论 (0)

请登录以参与评论
现在登录
    发表评论

猜你喜欢

  • 「日志记录」逆向必应翻译网页版API实现免费调用
  • 「代码分享」第三方平台VIP视频解析API接口
  • 「至臻原创」某系统网站登录功能监测
  • 「开发日志」在Vue3中如何为路由Query参数标注类型
  • 「其他分享」分享一个在Tun模式下可用的脚本
Eswlnk的头像

Eswlnk

一个有点倒霉的研究牲站长
1108
文章
319
评论
679
获赞

随便看看

「代码分享」通过PHP微信扫描关注公众号
2023-09-03 11:36:19
「玩物志趣」Additem在vb中怎么用?
2023-09-23 23:14:34
「代码分享」配置 Nuxt3 SEO | 站点地图 sitemap.xml 和 robots.txt
2024-04-13 13:38:11

文章目录

专题展示

WordPress53

工程实践37

热门标签

360 AI API CDN java linux Nginx PDF PHP python SEO Windows WordPress 云服务器 云服务器知识 代码 免费 安全 安卓 工具 开发日志 微信 微软 手机 插件 攻防 攻防对抗 教程 日志 渗透分析 源码 漏洞 电脑 破解 系统 编程 网站优化 网络 网络安全 脚本 苹果 谷歌 软件 运维 逆向
  • 首页
  • 知识库
  • 地图
Copyright © 2023-2025 Eswlnk Blog. Designed by XiaoWu.
本站CDN由 壹盾安全 提供高防CDN安全防护服务
蜀ICP备20002650号-10
页面生成用时 1.124 秒   |  SQL查询 53 次
本站勉强运行:
友情链接: Eswlnk Blog 网站渗透 倦意博客 特资啦!个人资源分享站 祭夜博客 iBAAO壹宝头条
  • WordPress142
  • 网络安全64
  • 漏洞52
  • 软件52
  • 安全48
现在登录
  • 资源
    • 精彩视频
    • 破解专区
      • WHMCS
      • WordPress主题
      • WordPress插件
    • 其他分享
    • 极惠VPS
    • PDF资源
  • 关于我
    • 论文阅读
    • 关于本站
    • 通知
    • 左邻右舍
    • 玩物志趣
    • 日志
    • 专题
  • 热议话题
    • 游戏资讯
  • 红黑
    • 渗透分析
    • 攻防对抗
    • 代码发布
  • 自主研发
    • 知识库
    • 插件
      • ToolBox
      • HotSpot AI 热点创作
    • 区块
    • 快乐屋
    • 卡密
  • 乱步
    • 文章榜单
    • 热门标签
  • 问答中心反馈