ecode

背景

错误码一般被用来进行异常传递,且需要具有携带message文案信息的能力。

错误码之Codes

kratos里,错误码被设计成Codes接口,声明如下代码位置

  1. // Codes ecode error interface which has a code & message.
  2. type Codes interface {
  3. // sometimes Error return Code in string form
  4. // NOTE: don't use Error in monitor report even it also work for now
  5. Error() string
  6. // Code get error code.
  7. Code() int
  8. // Message get code message.
  9. Message() string
  10. //Detail get error detail,it may be nil.
  11. Details() []interface{}
  12. }
  13. // A Code is an int error code spec.
  14. type Code int

可以看到该接口一共有四个方法,且type Code int结构体实现了该接口。

注册message

一个Code错误码可以对应一个message,默认实现会从全局变量_messages中获取,业务可以将自定义Code对应的message通过调用Register方法的方式传递进去,如:

  1. cms := map[int]string{
  2. 0: "很好很强大!",
  3. -304: "啥都没变啊~",
  4. -404: "啥都没有啊~",
  5. }
  6. ecode.Register(cms)
  7. fmt.Println(ecode.OK.Message()) // 输出:很好很强大!

注意:map[int]string类型并不是绝对,比如有业务要支持多语言的场景就可以扩展为类似map[int]LangStruct的结构,因为全局变量_messagesatomic.Value类型,只需要修改对应的Message方法实现即可。

Details

Details接口为gRPC预留,gRPC传递异常会将服务端的错误码pb序列化之后赋值给Details,客户端拿到之后反序列化得到,具体可阅读status的实现:

  1. ecode包内的Status结构体实现了Codes接口代码位置
  2. warden/internal/status包内包装了ecode.Statusgrpc.Status进行互相转换的方法代码位置
  3. wardenclientserver则使用转换方法将gRPC底层返回的error最终转换为ecode.Status 代码位置

转换为ecode

错误码转换有以下两种情况:

  1. 因为框架传递错误是靠ecode错误码,比如bm框架返回的code字段默认就是数字,那么客户端接收到如{"code":-404}的话,可以使用ec := ecode.Int(-404)ec := ecode.String("-404")来进行转换。
  2. 在项目中dao层返回一个错误码,往往返回参数类型建议为error而不是ecode.Codes,因为error更通用,那么上层service就可以使用ec := ecode.Cause(err)进行转换。

判断

错误码判断是否相等:

  1. ecodeecode判断使用:ecode.Equal(ec1, ec2)
  2. ecodeerror判断使用:ecode.EqualError(ec, err)

使用工具生成

使用proto协议定义错误码,格式如下:

  1. // user.proto
  2. syntax = "proto3";
  3. package ecode;
  4. enum UserErrCode {
  5. UserUndefined = 0; // 因protobuf协议限制必须存在!!!无意义的0,工具生成代码时会忽略该参数
  6. UserNotLogin = 123; // 正式错误码
  7. }

需要注意以下几点:

  1. 必须是enum类型,且名字规范必须以”ErrCode”结尾,如:UserErrCode
  2. 因为protobuf协议限制,第一个enum值必须为无意义的0

使用kratos tool protoc --ecode user.proto进行生成,生成如下代码:

  1. package ecode
  2. import (
  3. "github.com/go-kratos/kratos/pkg/ecode"
  4. )
  5. var _ ecode.Codes
  6. // UserErrCode
  7. var (
  8. UserNotLogin = ecode.New(123);
  9. )