package nstatus import ( "context" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" "google.golang.org/grpc/status" ) // UnaryServerInterceptor grpc 错误拦截 服务端拦截器 // 将服务端传递出的任何错误拦截并转换为标准grpc-status,保持code与msg,不进行翻译 // 将Result中的Type加入到metadata中进行传递 func UnaryServerInterceptor() grpc.UnaryServerInterceptor { return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) { resp, err = handler(ctx, req) if err != nil { e := ConvertErr(err) if e != nil { writeResultTypeCtx(ctx, e) // 转换为grpc-err err = status.Error(codes.Code(e.Code), e.Msg) } } return } } func writeResultTypeCtx(ctx context.Context, r *Result) { _ = grpc.SetHeader(ctx, metadata.Pairs(GrpcResultTypeKey, string(r.Type))) } // UnaryClientInterceptor 将客户端调用后产生的grpc-err转换为 *Result // 客户端直接强转为*Result 或 再次调用 ConvertErr 即可使用 func UnaryClientInterceptor() grpc.UnaryClientInterceptor { return func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error { err := invoker(ctx, method, req, reply, cc, opts...) if err == nil { return nil } e := ConvertErr(err) // 读取header(metadata)中的GrpcResultType md, ok := metadata.FromOutgoingContext(ctx) if ok { rt := md.Get(GrpcResultTypeKey) if len(rt) > 0 { e.Type = ResultType(rt[0]) } } return e } }