当业务需要复杂的错误码定义时,我们推荐灵活使用错误码的 Detail 参数来扩展错误码功能。

我们来看个示例,该示例主要实现以下几个功能:

  • 使用一个中间件识别路由函数的执行结果,并获取路由函数返回的错误码信息,将该错误码信息作为返回结果的一部分返回给调用端。
  • 如果产生了错误,会记录产生该错误的当前用户信息到日志中。该功能使用Detail扩展参数实现。

业务错误码

错误码定义

  1. type BizCode struct {
  2. User User
  3. // ...
  4. }
  5. type User struct {
  6. Id int
  7. Name string
  8. // ...
  9. }

错误码使用

扩展错误码大多数场景下需要使用 gcode.WithCode 方法:

  1. // WithCode creates and returns a new error code based on given Code.
  2. // The code and message is from given `code`, but the detail if from given `detail`.
  3. func WithCode(code Code, detail interface{}) Code

因此上面我们的自定义扩展可以这么使用:

  1. code := gcode.WithCode(gcode.CodeNotFound, BizCode{
  2. User: User{
  3. Id: 1,
  4. Name: "John",
  5. },
  6. })
  7. fmt.Println(code)

即在错误码中我们可以根据业务场景注入一些自定义的错误码扩展数据,以方便上层获取错误码后做进一步处理。

改写中间件

我们将上面自定义的错误码应用到请求返回中间件中,顶层业务逻辑也可以获取到错误码对应的详情再进一步做相关的业务处理。中间件返回的数据结构也可以自定义重写,例如其中返回的 code 字段也不一定是整形数值,可以完全自定义。

  1. func ResponseHandler(r *ghttp.Request) {
  2. r.Middleware.Next()
  3. // There's custom buffer content, it then exits current handler.
  4. if r.Response.BufferLength() > 0 {
  5. return
  6. }
  7. var (
  8. err = r.GetError()
  9. res = r.GetHandlerResponse()
  10. code = gerror.Code(err)
  11. )
  12. if code == gcode.CodeNil && err != nil {
  13. code = gcode.CodeInternalError
  14. }
  15. if detail, ok := code.Detail().(BizCode); ok {
  16. g.Log().Errorf(r.Context(), `error caused by user "%+v"`, detail.User)
  17. }
  18. r.Response.WriteJson(ghttp.DefaultHandlerResponse{
  19. Code: gcode.CodeOK.Code(),
  20. Message: gcode.CodeOK.Message(),
  21. Data: res,
  22. })
  23. }

错误处理-错误码扩展 - 图1提示

在框架 Server 默认的日志中会自动打印 Detail 数据。