go-zero 错误处理

2022-04-21 11:04 更新

错误处理

错误的处理是一个服务必不可缺的环节。在平时的业务开发中,我们可以认为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.go
  package errorx

  const defaultCode = 1001

  type 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.AccessExpire
      jwtToken, 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.go
  func main() {
      flag.Parse()

      var c config.Config
      conf.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 OK
  Content-Type: application/json
  Date: Tue, 09 Feb 2021 06:47:29 GMT
  Content-Length: 40

  {"code":1001,"msg":"用户名不存在"}


以上内容是否对您有帮助:
在线笔记
App下载
App下载

扫描二维码

下载编程狮App

公众号
微信公众号

编程狮公众号