自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

學(xué)會定制化 Go 項目的 error,回溯錯誤的原因和發(fā)生位置

開發(fā) 前端
如果你們的研發(fā)習(xí)慣是請求接口的響應(yīng)一律是 HTTP 200 再通過相應(yīng)里的code碼判斷是否正確,這個方法可以放著不用, 規(guī)范化一點(diǎn)肯定是這種比較好,況且HTTP Status 不是 200 狀態(tài)碼,也是可以返回 code msg 那些信息給客戶端的。

Go語言的Error處理一直被人吐槽,吐槽的點(diǎn)除了一個接一個的 if err != nil 的判斷外,還有人說Go的錯誤太原始不能像其他語言那樣在拋出異常的時候的時候傳一個Casue Exception 把導(dǎo)致異常的整個原因鏈串起來。

第一點(diǎn)確實(shí)是事實(shí),但是寫習(xí)慣了也能接受,而且對新手友好。第二點(diǎn)屬實(shí)就有點(diǎn)尬黑了。

用Go開發(fā)項目時想讓程序拋出的 error 信息不要那么單薄,需要自己搭建項目時先做一番基礎(chǔ)工作,自己定義項目的Error類型在包裝錯誤的時候記錄上錯誤的原因和發(fā)生的位置,比如像下面這樣。

{
    "code": 10000000,
    "msg": "服務(wù)器內(nèi)部錯誤",
    "cause": "db error: undefined column user_id",
    "occurred": "go-study-lab/go-mall.TestAppError, file: building.go, line: 69"
}

同時它還要實(shí)現(xiàn)Go的error interface,能融入Go 的錯誤處理機(jī)制才行。

今天我就帶大家通過自定義項目Error并實(shí)現(xiàn) Go error interface ,讓你的Go項目Error擁有更豐富的錯誤原因和發(fā)生位置的信息??吹揭粋€錯誤能看出來時什么原因?qū)е碌?、以及是哪的代碼導(dǎo)致的這樣能大大降低Go項目的維護(hù)難度。

Go Error 定制化Go Error 定制化

定義項目的Error結(jié)構(gòu)

首先我們在項目的common目錄中增加errcode目錄,該目錄下會創(chuàng)建兩個文件error.go 和 code.go。error.go文件用來存放自定義Error的結(jié)構(gòu)和相關(guān)方法,code.go 用來放置項目各種預(yù)定義的Error。

.
|-- common
|   |-- errcode
|       |---code.go
|       |---error.go
|-- main.go
|-- go.mod
|-- go.sum

我們現(xiàn)在error.go 中定義AppError

type AppError struct {
 code     int    `json:"code"`
 msg      string `json:"msg"`
 cause    error  `json:"cause"`
}

cause 字段保存的是導(dǎo)致產(chǎn)生 AppErr 的原因,比如一個數(shù)據(jù)庫查詢語法錯誤,拿它再來生成項目的 AppError 或者是給預(yù)定義好的 AppError 追加上這個原因的error, 這樣就能達(dá)到保存錯誤鏈條的目的。

現(xiàn)在AppError 還不是 error 類型,需要讓他實(shí)現(xiàn)Go的 error interface,這個接口如下。

type error interface {
 Error() string
}

其中只定義了一個方法,我們讓AppError實(shí)現(xiàn)Error方法把它變成 error 類型。

func (e *AppError) Error() string {
 if e == nil {
  return ""
 }

 formattedErr := struct {
  Code     int    `json:"code"`
  Msg      string `json:"msg"`
  Cause    string `json:"cause"`
 }{
  Code:     e.Code(),
  Msg:      e.Msg(),
 }

 if e.cause != nil {
  formattedErr.Cause = e.cause.Error()
 }
 errByte, _ := json.Marshal(formattedErr)
 return string(errByte)
}

Error方法返回的是AppError對象的JSON序列化字符串,其中如果cause字段不為空即錯誤原因不為空,再去錯誤原因的Error方法拿到底層的錯誤信息。

我們把Stringer 接口也實(shí)現(xiàn)一下,在沒有類型字段轉(zhuǎn)換的地方,它還是*AppErr類型,保證這個時候序列化它的時候仍然能得到期望的信息。

func (e *AppError) String() string {
 return e.Error()
}

接下來我們在code.go 中先預(yù)定義一些基礎(chǔ)的錯誤

var (
 Success            = newError(0, "success")
 ErrServer          = newError(10000000, "服務(wù)器內(nèi)部錯誤")
 ErrParams          = newError(10000001, "參數(shù)錯誤, 請檢查")
 ErrNotFound        = newError(10000002, "資源未找到")
 ErrPanic           = newError(10000003, "(*^__^*)系統(tǒng)開小差了,請稍后重試") // 無預(yù)期的panic錯誤
 ErrToken           = newError(10000004, "Token無效")
 ErrForbidden       = newError(10000005, "未授權(quán)") // 訪問一些未授權(quán)的資源時的錯誤
 ErrTooManyRequests = newError(10000006, "請求過多")
)

上面大家看到了 AppError 的類型定義中,字段的訪問性都是包內(nèi)可訪問的,所以我們要定義一些 getter 方法,這樣接口返回錯誤響應(yīng)時,才能讀到錯誤碼和錯誤信息。

func (e *AppError) Code() int {
 return e.code
}

func (e *AppError) Msg() string {
 return e.msg
}

func (e *AppError) HttpStatusCode() int {
 switch e.Code() {
 case Success.Code():
  return http.StatusOK
 case ErrServer.Code(), ErrPanic.Code():
  return http.StatusInternalServerError
 case ErrParams.Code():
  return http.StatusBadRequest
 case ErrNotFound.Code():
  return http.StatusNotFound
 case ErrTooManyRequests.Code():
  return http.StatusTooManyRequests
 case ErrToken.Code():
  return http.StatusUnauthorized
 case ErrForbidden.Code():
  return http.StatusForbidden
 default:
  return http.StatusInternalServerError
 }
}

這里的 HttpStatusCode 返回的是HTTP 狀態(tài)碼,如果你們的研發(fā)習(xí)慣是請求接口的響應(yīng)一律是 HTTP 200 再通過相應(yīng)里的code碼判斷是否正確,這個方法可以放著不用, 規(guī)范化一點(diǎn)肯定是這種比較好,況且HTTP Status 不是 200 狀態(tài)碼,也是可以返回 code msg 那些信息給客戶端的。

底層Error怎么變成項目Error

上面我們預(yù)定義好了幾個應(yīng)用錯誤,這里說明一下,預(yù)定義好的錯誤會最終返回給發(fā)起請求的客戶端,所以控制器層各個URI的路由處理控制器中最后一定要返回預(yù)定義的錯誤,這個我們會在未來給Go項目封裝統(tǒng)一的響應(yīng)組件時處理。

那一個底層的錯誤怎么才能變成我們自定義的錯誤呢?

責(zé)任編輯:武曉燕 來源: 網(wǎng)管叨bi叨
相關(guān)推薦

2024-10-30 09:29:30

Go項目Error

2025-03-31 00:29:44

2022-11-09 11:50:21

2024-12-17 09:14:48

項目http 庫API

2020-10-10 07:14:08

前端項目斷點(diǎn)

2023-02-07 07:16:54

人工智能機(jī)器學(xué)習(xí)方法

2020-08-07 11:46:47

JavaScript開發(fā)代碼

2022-07-19 08:01:55

函數(shù)Go格式化

2010-08-02 08:54:53

Flex模塊化

2009-07-20 15:51:45

JDBC連接Oracl

2024-02-21 19:02:05

Go模板化方式

2021-01-25 10:30:52

數(shù)字化分析轉(zhuǎn)型首席執(zhí)行官

2021-06-29 10:01:56

物聯(lián)網(wǎng)項目eSIM物聯(lián)網(wǎng)

2018-06-12 15:55:44

數(shù)字化項目

2022-10-09 14:50:24

前端pnpm工具

2023-09-07 07:53:21

JavaScriptGoRust

2022-05-17 08:02:55

GoTryLock模式

2020-06-05 08:29:40

語言PythonGo

2014-04-23 13:45:40

iOS項目目錄結(jié)構(gòu)開發(fā)流程

2018-06-29 10:34:40

區(qū)塊鏈數(shù)字貨幣比特幣
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號