错误处理
错误的处理是一个服务必不可缺的环节。在平时的业务开发中,我们可以认为http状态码不为2xx
系列的,都可以认为是http请求错误,
并伴随响应的错误信息,但这些错误信息都是以plain text形式返回的。除此之外,我在业务中还会定义一些业务性错误,常用做法都是通过
code
、msg
两个字段来进行业务处理结果描述,并且希望能够以json响应体来进行响应。
业务错误响应格式#
业务处理正常
{"code": 0,"msg": "successful","data": {....}}业务处理异常
{"code": 10001,"msg": "参数错误"}
user api之login#
在之前,我们在登录逻辑中处理用户名不存在时,直接返回来一个error。我们来登录并传递一个不存在的用户名看看效果。
curl -X POST \
http://127.0.0.1:8888/user/login \
-H 'content-type: application/json' \
-d '{
"username":"1",
"password":"123456"
}'
HTTP/1.1 400 Bad Request
Content-Type: text/plain; charset=utf-8
X-Content-Type-Options: nosniff
Date: Tue, 09 Feb 2021 06:38:42 GMT
Content-Length: 19
用户名不存在
接下来我们将其以json格式进行返回
自定义错误#
首先在common中添加一个
baseerror.go
文件,并填入代码$ cd common$ mkdir errorx && cd errorx$ vim baseerror.gopackage errorxconst defaultCode = 1001type CodeError struct {Code int `json:"code"`Msg string `json:"msg"`}type CodeErrorResponse struct {Code int `json:"code"`Msg string `json:"msg"`}func NewCodeError(code int, msg string) error {return &CodeError{Code: code, Msg: msg}}func NewDefaultError(msg string) error {return NewCodeError(defaultCode, msg)}func (e *CodeError) Error() string {return e.Msg}func (e *CodeError) Data() *CodeErrorResponse {return &CodeErrorResponse{Code: e.Code,Msg: e.Msg,}}将登录逻辑中错误用CodeError自定义错误替换
if len(strings.TrimSpace(req.Username)) == 0 || len(strings.TrimSpace(req.Password)) == 0 {return nil, errorx.NewDefaultError("参数错误")}userInfo, err := l.svcCtx.UserModel.FindOneByNumber(req.Username)switch err {case nil:case model.ErrNotFound:return nil, errorx.NewDefaultError("用户名不存在")default:return nil, err}if userInfo.Password != req.Password {return nil, errorx.NewDefaultError("用户密码不正确")}now := time.Now().Unix()accessExpire := l.svcCtx.Config.Auth.AccessExpirejwtToken, err := l.getJwtToken(l.svcCtx.Config.Auth.AccessSecret, now, l.svcCtx.Config.Auth.AccessExpire, userInfo.Id)if err != nil {return nil, err}return &types.LoginReply{Id: userInfo.Id,Name: userInfo.Name,Gender: userInfo.Gender,AccessToken: jwtToken,AccessExpire: now + accessExpire,RefreshAfter: now + accessExpire/2,}, nil开启自定义错误
$ vim service/user/api/user.gofunc main() {flag.Parse()var c config.Configconf.MustLoad(*configFile, &c)ctx := svc.NewServiceContext(c)server := rest.MustNewServer(c.RestConf)defer server.Stop()handler.RegisterHandlers(server, ctx)// 自定义错误httpx.SetErrorHandler(func(err error) (int, interface{}) {switch e := err.(type) {case *errorx.CodeError:return http.StatusOK, e.Data()default:return http.StatusInternalServerError, nil}})fmt.Printf("Starting server at %s:%d...\n", c.Host, c.Port)server.Start()}重启服务验证
$ curl -i -X POST \http://127.0.0.1:8888/user/login \-H 'content-type: application/json' \-d '{"username":"1","password":"123456"}'HTTP/1.1 200 OKContent-Type: application/jsonDate: Tue, 09 Feb 2021 06:47:29 GMTContent-Length: 40{"code":1001,"msg":"用户名不存在"}