go-zero rpc错误处理 | 青训营笔记

980 阅读2分钟

这是我参与「第五届青训营」伴学笔记创作活动的第 4 天

目前应该很少有企业选择服务单机运行了,几乎都选择了容器化部署,模块拆分,来防止各个模块之间造成的影响。同时也有利于扩容。

基本架构

在开发过程中,我选择直接使用 go-zero 提供的 Api 作为服务网关,与其他服务之间采用 Rpc 进行通信。

比如我选择将用户验证identity作为一个单独的服务,只负责处理用户登录,用户注册,身份验证

Api 类似:

syntax = "v1"

type registerReq {
   Username string `form:"username"`
   Password string `form:"password"`
}


@server(
   group: identity
)
service gateway {
   @handler register
   post /douyin/user/register (registerReq)
}

Identity 服务:

syntax = "proto3";

package identity;

option go_package = "./identity";

message Resp {
    int32 status_code = 1;
    string status_msg = 2;
}

message registerReq {
  string username = 1;
  string password = 2;
}

message registerResp {
  Resp response = 1;
  int64 user_id = 2;
  string token = 3;
}

service identity {
  rpc register(registerReq) returns (registerResp);
}

遇到的问题

在 rpc 服务中,我使用了自己定义的错误

type Error interface {
   error
   Error() string
}

type RespError struct {
   Code int32  `json:"code"`
   Msg  string `json:"msg"`
}

func (e *RespError) Error() string {
   return fmt.Sprintf("err_code: %d, err_msg: %s", e.Code, e.Msg)
}

当遇到错误时,便会返回rpcResponse{}, *RespError

由于 Gateway 对于前端要求输出格式统一,默认情况下,Gateway 在接受到 rpc服务 返回的错误时,会直接输出类似 rpc error:: code = Unknow desc = code: xxx ,msg: xxxGateway 无法很好的对其进行解析。

解决方案

go-zero 的文档并不全,一开始我是跟着文档中所描述,在 Gateway 中使用 httpx.SetErrorHandlerCtx对其错误进行拦截,达到自定义错误的方式。 但 rpc服务 返回的 error 比较奇怪,在尝试过使用 error.As 对其进行转换后,也无法获取定义的 CodeMsg.

最终,在阅读了下 go-zero 的源码后,发现要求返回的错误,似乎是 Grpc 中的 status.Status. 我们可以通过 status.Error() 生成错误。 这样在 Gateway 中便可以通过 status.FromError() 对其进行解析。