折腾了一天,算是找到了一种解决方法
就是我现在需要在调用 rpc 时传递全局错误,我定义的全局错误如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
| package rpcError
type Code int
const ( ErrPersonNotExistCode Code = iota + 1000 ErrPersonCreateFailedCode ErrPersonUpdateFailedCode ErrPersonDeleteFailedCode
ErrClassNotExistCode Code = iota + 2000 ErrClassCreateFailedCode ErrClassUpdateFailedCode ErrClassDeleteFailedCode ErrClassGetListFailedCode
ErrRedisSetFailedCode Code = iota + 3000 ErrRedisGetFailedCode )
var errCodeMap = map[Code]string{ ErrPersonNotExistCode: "用户不存在", ErrPersonCreateFailedCode: "用户创建失败", ErrPersonUpdateFailedCode: "用户更新失败", ErrPersonDeleteFailedCode: "用户删除失败",
ErrClassNotExistCode: "班级不存在", ErrClassCreateFailedCode: "班级创建失败", ErrClassUpdateFailedCode: "班级更新失败", ErrClassDeleteFailedCode: "班级删除失败", ErrClassGetListFailedCode: "班级列表获取失败",
ErrRedisSetFailedCode: "redis缓存失败", ErrRedisGetFailedCode: "redis获取失败", }
var ( ErrPersonNotExist = NewRpcError(ErrPersonNotExistCode) ErrPersonCreateFailed = NewRpcError(ErrPersonCreateFailedCode) ErrPersonUpdateFailed = NewRpcError(ErrPersonUpdateFailedCode) ErrPersonDeleteFailed = NewRpcError(ErrPersonDeleteFailedCode)
ErrClassNotExist = NewRpcError(ErrClassNotExistCode) ErrClassCreateFailed = NewRpcError(ErrClassCreateFailedCode) ErrClassUpdateFailed = NewRpcError(ErrClassUpdateFailedCode) ErrClassDeleteFailed = NewRpcError(ErrClassDeleteFailedCode) ErrClassGetListFailed = NewRpcError(ErrClassGetListFailedCode)
ErrRedisSetFailed = NewRpcError(ErrRedisSetFailedCode) ErrRedisGetFailed = NewRpcError(ErrRedisGetFailedCode) )
type RpcError struct { Code Code `json:"code"` Message string `json:"message"` }
func NewRpcError(code Code) *RpcError { return &RpcError{ Code: code, Message: errCodeMap[code], } }
func (e *RpcError) Error() string { return e.Message }
|
但是,rpc 传递过去之后,grpc给他又封装了一层,就不能用 errors.Is()
来判断了
然后折腾了好久,最后经人指点可以使用 gppc 的 state 来传递错误码(
先把全局错误码改成 codes.Code
类型,然后自己写一个函数用来比较
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| type RpcError struct { Code codes.Code `json:"code"` Message string `json:"message"` }
func Is(err error, target *RpcError) bool {
if err == nil { return false }
s, _ := status.FromError(err)
return s.Code() == target.Code }
|
然后在 rpc 层和 api 层这样使用
1 2 3 4 5
| err = l.svcCtx.DBList.Mysql.First(&classModel).Error if err != nil { return &class.GetPersonReply{}, status.Error(rpcError.ErrClassNotExist.Code, err.Error()) }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
GetPersonResult, err := l.svcCtx.ClassRpc.GetPerson(l.ctx, &class.GetPersonRequest{ Id: int32(studentId), })
if err == nil { } else if rpcError.Is(err, rpcError.ErrPersonNotExist) { } else { return "", errors.New("get user info failed") }
|
但是我还是不能理解官方文档是怎么直接比较的