设为首页 加入收藏

TOP

grpc错误处理(二)
2023-07-23 13:29:45 】 浏览:66
Tags:grpc
", reply.Value) }

我们可以看下status.FromError的返回结果:

  • 如果 err 是由这个包产生的或者实现了方法 GRPCStatus() *Status,返回相应的状态。
  • 如果 err 为 nil,则返回带有代码的状态。OK 并且没有消息。
  • 否则,err 是与此包不兼容的错误。 在这个情况下,返回一个 Status 结构是 code.Unknown 和 err 的 Error() 消息,并且ok为false。

我们重新执行下客户端代码:

go run helloclient/main.go
invoker request time duration:  1
2022/10/16 23:26:11 invalid arguments
exit status 1

可以看到,当服务端返回的是codes.InvalidArgument错误时,我们重新定义了错误。

3、获取grpc错误更详细的信息

当我们服务端返回grpc错误时,我们想带上一些自定义的详细错误信息,这个时候就可以像下面这样写:

func (h HelloService) Hello(ctx context.Context, args *String) (*String, error) {
	time.Sleep(time.Second)
	if args.GetValue() != "hello" {
		errorStatus := status.New(codes.InvalidArgument, "请求参数错误")
		details, err := errorStatus.WithDetails(&errdetails.BadRequest_FieldViolation{
			Field:       "string.value",
			Description: fmt.Sprintf("expect hello, get %s", args.GetValue()),
		})
		if err != nil {
			return nil, errorStatus.Err()
		}
		return nil, details.Err()
	}
	reply := &String{Value: "hello:" + args.GetValue()}
	return reply, nil
}

我们重点看下WithDetails方法:

  • 该方法传入一个proto.Message类型的数组,Message是一个protocol buffer的消息
  • 返回一个新Status,并将提供的详细信息消息附加到Status
  • 如果遇到任何错误,则返回 nil 和遇到的第一个错误

然后我们修改下客户端代码:

func unaryRpc(conn *grpc.ClientConn) {
	client := helloservice.NewHelloServiceClient(conn)
	ctx := context.Background()
	md := metadata.Pairs("authorization", "mytoken")
	ctx = metadata.NewOutgoingContext(ctx, md)
	reply, err := client.Hello(ctx, &helloservice.String{Value: "f**k"})
	if err != nil {
		fromError, ok := status.FromError(err)
		if !ok {
			log.Fatal(err)
		}
		if fromError.Code() == codes.InvalidArgument {
      // 获取错误的详细信息,因为详细信息返回的是数组,所以这里我们需要遍历
			for _, detail := range fromError.Details() {
				detail = detail.(*proto.Message)
				log.Println(detail)
			}
			log.Fatal("invalid arguments")
		}
	}
	log.Println("unaryRpc recv: ", reply.Value)
}

接着重启下服务端,运行下客户端代码:

go run helloclient/main.go
invoker request time duration:  1
2022/10/16 23:58:51 field:"string.value"  description:"expect hello, get f**k"
2022/10/16 23:58:51 invalid arguments
exit status 1

可以看到详细信息打印出来了。

4、定义标准错误之外的错误

现实中我们可能会有这样的要求:

  • 当grpc服务端是自定义错误时,客户端返回自定义错误
  • 当grpc服务端返回的是标准错误时,客户端返回系统错误

我们可以创建一个自定义测错误类:

package xerr

import (
	"fmt"
)

/**
常用通用固定错误
*/
type CodeError struct {
	errCode uint32
	errMsg  string
}

//返回给前端的错误码
func (e *CodeError) GetErrCode() uint32 {
	return e.errCode
}

//返回给前端显示端错误信息
func (e *CodeError) GetErrMsg() string {
	return e.errMsg
}

func (e *CodeError) Error() string {
	return fmt.Sprintf("ErrCode:%d,ErrMsg:%s", e.errCode, e.errMsg)
}

然后grpc服务端实现一个拦截器,目的是把自定义错误转换成grpc错误:

func LoggerInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {

	resp, err = handler(ctx, req)
	if err != nil {
		causeErr := errors.Cause(err)                // err类型
		if e, ok := causeErr.(*xerr.CodeError); ok { //自定义错误类型

			//转成grpc err
			err = status.Error(codes.Code(e.GetErrCode()), e.GetErrMsg())
		} 

	}

	return resp, err
}

然后客户端处理错误代码的部分修改如下:

//错误返回
	
		causeErr := errors.Cause(err)                // err类型
		if e, ok := caus
首页 上一页 1 2 3 下一页 尾页 2/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇golang开发一个简单的grpc 下一篇golang中的切片

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目