Error Handling

[!TIP] This document is machine-translated by Google. If you find grammatical and semantic errors, and the document description is not clear, please PR

Error handling is an indispensable part of service. In normal business development, we can think that the http status code is not in the 2xx series, it can be regarded as an http request error. It is accompanied by error messages in response, but these error messages are all returned in plain text. In addition, I will define some business errors in the business, and the common practice is to pass The two fields code and msg are used to describe the business processing results, and it is hoped that the response can be made with the json response body.

Business error response format

  • Business processing is normal

      {
        "code": 0,
        "msg": "successful",
        "data": {
          ....
        }
      }
    
  • Business processing exception

      {
        "code": 10001,
        "msg": "something wrong"
      }
    

login of user api

Previously, when we handled the login logic when the username did not exist, an error was directly returned. Let's log in and pass a username that does not exist to see the effect.

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

Username does not exist

Next we will return it in json format

Custom error

  • First add a baseerror.go file in common and fill in the code

      $ 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,
          }
      }
    
  • Replace errors in login logic with CodeError custom errors

      if len(strings.TrimSpace(req.Username)) == 0 || len(strings.TrimSpace(req.Password)) == 0 {
              return nil, errorx.NewDefaultError("Invalid parameter")
          }
    
          userInfo, err := l.svcCtx.UserModel.FindOneByNumber(req.Username)
          switch err {
          case nil:
          case model.ErrNotFound:
              return nil, errorx.NewDefaultError("Username does not exist")
          default:
              return nil, err
          }
    
          if userInfo.Password != req.Password {
              return nil, errorx.NewDefaultError("User password is incorrect")
          }
    
          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
    
  • Use custom errors

      $ vim service/user/cmd/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)
    
          // Custom error
          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()
      }
    
  • Restart service verification

      $ 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":"Username does not exist"}
    
Copyright © 2019-2021 go-zero all right reserved,powered by GitbookLast UpdateTime: 2021-12-05 09:48:50

results matching ""

    No results matching ""