在之前的文章中,我們嘗試重復注冊的時候,給我們返回來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