日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
Go語言錯誤處理為什么更推薦使用Pkg/Errors三方庫?

?1.介紹

其中,我們用的最多的是 New?,但是,在我們實際 Go 項目開發(fā)中,會使用一些分層設(shè)計,比如 MVC,Clean Architecture 等。

衡水網(wǎng)站建設(shè)公司創(chuàng)新互聯(lián)公司,衡水網(wǎng)站設(shè)計制作,有大型網(wǎng)站制作公司豐富經(jīng)驗。已為衡水千余家提供企業(yè)網(wǎng)站建設(shè)服務(wù)。企業(yè)網(wǎng)站搭建\外貿(mào)網(wǎng)站建設(shè)要多少錢,請找那個售后服務(wù)好的衡水做網(wǎng)站的公司定做!

在使用分層設(shè)計的項目中,如果我們使用 Go 標準庫 errors 定義錯誤,就會遇到錯誤覆蓋的問題。

2.關(guān)于標準庫 errors 的錯誤覆蓋問題

Go標準庫 errors? 的 New? 方法,只能定義一條簡單的錯誤信息,在分層設(shè)計的項目代碼中,就會遇到錯誤覆蓋的問題,比如我們本文的示例項目代碼,使用的是 Clean Architecture 分層設(shè)計。

項目分層目錄:

.
├── 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)
}

閱讀上面三段代碼,我們可以發(fā)現(xiàn),我們在每層中都有錯誤處理的代碼,我們故意使用錯誤的請求參數(shù),并將數(shù)據(jù)庫連接的密碼寫錯,觸發(fā)應(yīng)用程序的錯誤。

輸出結(jié)果:

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

閱讀輸出結(jié)果,我們可以發(fā)現(xiàn),usecase 層定義的錯誤,被調(diào)用的 repository 層返回錯誤覆蓋;delivery 層定義的錯誤將 usecase 層返回的錯誤覆蓋。

因為我們在每層都打印了錯誤,仔細排查,還是可以定位到錯誤,但是還是比較繁瑣,不僅每層打印錯誤使代碼不夠優(yōu)雅,而且也不能快速定位到錯誤。

怎么解決這個問題呢?使用三方庫 github.com/pkg/errors? 替換 Go 標準庫 errors。

3.三方庫 pkg/errors

使用三方庫 pkg/errors 可以解決在分層設(shè)計的項目中調(diào)用堆棧的錯誤信息互相覆蓋,可以為我們輸出錯誤的堆棧信息,可以在已有錯誤信息的基礎(chǔ)上附加新的錯誤信息,從而解決輸出的錯誤信息缺失上下文的問題。

我們修改一下 Part 02 的示例代碼,將 Go 標準庫 errors? 替換為三方庫 pkg/errors?,相信細心的讀者朋友們已經(jīng)發(fā)現(xiàn),因為這兩個包的名字相同,而且都有 New 方法,所以替換起來也比較方便,只需替換導入的包。

示例代碼:

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

替換后的輸出結(jié)果:

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

閱讀上面的輸出結(jié)果,我們可以發(fā)現(xiàn)錯誤處理包由 Go 標準庫 errors? 替換為三方庫 pkg/errors? 后,輸出結(jié)果不僅有 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 方法,它可以在已有錯誤信息的基礎(chǔ)上,附加新的錯誤信息和錯誤的堆棧信息。

輸出結(jié)果:

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

閱讀以上輸出結(jié)果,我們可以發(fā)現(xiàn)在 delivery 層定義的錯誤信息,沒有再覆蓋調(diào)用 usecase 層方法返回的錯誤信息,二者都被正常輸出。

需要注意的是,同時輸出錯誤信息和堆棧信息,占位符需要使用 %+v,也不要在每層都輸出堆棧信息,這樣會重復打印堆棧信息,通常做法是如果下層打印了堆棧信息,上層就不要再打印堆棧信息。

此外,三方庫 pkg/errors? 的另外兩個方法 WithMessage? 和 WithStack 也比較常用,它們分別是在已有的錯誤信息的基礎(chǔ)上,附加新的錯誤信息和錯誤的堆棧信息,我們在實際項目開發(fā)中,可以按需選擇使用合適的方法。

4.總結(jié)

本文我們講述了使用 Go 標準庫 errors? 進行錯誤處理的局限性和不足,為了解決它的不足,我們介紹了使用三方庫 pkg/errors? 替換 Go 標準庫 errors?,和三方庫 pkg/errors 的幾個常用方法的使用方式。

關(guān)于三方庫 pkg/errors 的更多方法,感興趣的讀者朋友們可以閱讀文檔了解如何使用。


本文名稱:Go語言錯誤處理為什么更推薦使用Pkg/Errors三方庫?
地址分享:http://www.dlmjj.cn/article/coohcjs.html