go-zero(四) 錯誤處理(統(tǒng)一響應信息)

在之前的文章中,我們嘗試重復注冊的時候,給我們返回來400狀態(tài)碼,這樣不利于前端來做用戶提示。


image.png

在api服務中,我們希望http接口返回的狀態(tài)碼code永遠是200,通過業(yè)務自定義的錯誤碼來區(qū)分業(yè)務錯誤或者服務內(nèi)部錯誤。

當返回錯誤的時候,http接口同樣也返回json格式的數(shù)據(jù),code為業(yè)務自定義的錯誤碼,message為自定義錯誤碼的詳細描述,客戶端獲取到該數(shù)據(jù)后可以判斷該業(yè)務錯誤碼,同時可以把message信息做一個錯誤彈窗處理。

{
    "code": 1,
    "msg": "用戶已經(jīng)注冊"
}

一、自定義錯誤處理方法和自定義錯誤碼

自定義錯誤處理方法,需要使用httpx.SetErrorHandler(),來捕捉錯誤信息。

1.自定義錯誤結構與格式化

我們在項目所在目錄下新建biz目錄,然后再這個目錄下分別創(chuàng)建3個文件

err.go 用來定義錯誤結構:

package biz

type Error struct {
    Code int    `json:"code"`
    Msg  string `json:"msg"`
}

func (e *Error) Error() string {
    return e.Msg
}

func NewError(code int, msg string) *Error {
    return &Error{
        Code: code,
        Msg:  msg,
    }
}

resp.go 用來處理錯誤響應

package biz

type Result struct {
    Code int    `json:"code"`
    Msg  string `json:"msg"`
    Data any    `json:"data"`
}

func Success(data any) *Result {
    return &Result{
        Code: Ok,
        Msg:  "success",
        Data: data,
    }
}

func Fail(err *Error) *Result {
    return &Result{
        Code: err.Code,
        Msg:  err.Msg,
    }
}

func ErrHandler(err error) (int, any) {
    switch e := err.(type) {
    case *Error:
        // 自定義一個 錯誤返回類型
        return http.StatusOK, Fail(e)
    default:
        return http.StatusInternalServerError, nil
    }
}

vars.go 用來定義比較通用的業(yè)務錯誤碼

package biz

const Ok = 200

var (
    AlreadyRegister = NewError(1, "用戶已注冊")
    PasswordErr     = NewError(2, "密碼錯誤")
    InsertErr       = NewError(3, "用戶注冊失敗")
    /*
    .....
    */
)


2. 使用自定義錯誤

接著修改user.go 文件,在main函數(shù)中使用自定義錯誤處理方法:

    /*
    ....
    */
    defer server.Stop()
    
    //httpx.SetErrorHandler 函數(shù)可以幫助你定義一個全局的錯誤處理邏輯,
    //該邏輯會在 HTTP handler 中捕獲到的所有錯誤中執(zhí)行。
    //它將允許你統(tǒng)一處理各類錯誤,返回更加一致和用戶友好的響應。
    //httpx.SetErrorHandler 僅在調(diào)用了 httpx.Error 處理響應時才有效。
    httpx.SetErrorHandler(biz.ErrHandler)

    ctx := svc.NewServiceContext(c)
        /*
    ....
    */

接著修改業(yè)務代碼,我們還是以注冊功能為例,把返回的錯誤信息修改成我們自定義錯誤:

func (l *RegisterLogic) Register(req *types.RegisterRequest) (resp *types.RegisterResponse, err error) {
    // todo: add your logic here and delete this line
    /*
    ...
    */
    if user != nil {
        
        //return nil, errors.New(1, "用戶已注冊")
        return nil, biz.AlreadyRegister
    }
    //插入新的數(shù)據(jù)
    /*
    ...
    */
    if err != nil {
        //return nil, errors.New(2, "用戶注冊失敗")
        return nil, biz.InsertErr
    }

}

接著運行測試


image.png

二、使用第三方庫

如果你不想自己編寫錯誤處理方法,也可以使用go zero 官方提供的X倉庫,可以實現(xiàn)統(tǒng)一響應格式

1.下載庫

go get github.com/zeromicro/x

它會自動幫我們把響應信息改為下面這種格式:

{
  "code": 0,
  "msg": "ok",
  "data": {
    ...
  }
}

2.修改handler

使用這個庫需要我們修改handler,把原來的錯誤處理替換掉:

//導入zeromicro庫并設置別名,避免和原生的http沖突
import (
    xhttp "github.com/zeromicro/x/http"  
)

//修改RegisterHandler的返回信息
func RegisterHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        var req types.RegisterRequest
        if err := httpx.Parse(r, &req); err != nil {
            //使用xhttp.JsonBaseResponseCtx 替換掉httpx.ErrorCtx
            xhttp.JsonBaseResponseCtx(r.Context(), w, err)
            //httpx.ErrorCtx(r.Context(), w, err)
            return
        }

        l := register.NewRegisterLogic(r.Context(), svcCtx)
        resp, err := l.Register(&req)
        if err != nil {
            //使用xhttp.JsonBaseResponseCtx 替換掉httpx.ErrorCtx
            xhttp.JsonBaseResponseCtx(r.Context(), w, err)
            //httpx.ErrorCtx(r.Context(), w, err)
        } else {
            //使用xhttp.JsonBaseResponseCtx 替換掉httpx.OkJsonCtx
            xhttp.JsonBaseResponseCtx(r.Context(), w, resp)
            //httpx.OkJsonCtx(r.Context(), w, resp)
        }
    }
}

3.修改返回錯誤

在業(yè)務文件中,把原來的err 修改成 errors.New() ,它的參數(shù)有兩個,一個是用來返回 code碼 ,還有一個是message消息:

func (l *RegisterLogic) Register(req *types.RegisterRequest) (resp *types.RegisterResponse, err error) {
    // todo: add your logic here and delete this line
    /*
    .....
    */
    
    if user != nil {
        //return nil, err
        return nil, errors.New(1, "用戶已注冊")
    }
    //插入新的數(shù)據(jù)
    /*
    .....
    */
    if err != nil {
        //return nil, err
        return nil, errors.New(2, "用戶注冊失敗")
    }
}

接著我們運行項目,使用Postman重新測試,結果如下:


image.png
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容