为什么我无法转换回通过 gRPC 调用接收到的特定接口?

问题描述 投票:0回答:1

什么

我想通过 gRPC 调用返回一个实现两个接口

error
和我的自定义接口
Hater
的结构。

返回结构将作为错误返回。

func (s ErrorTestServer) ErrorTest(ctx context.Context, _ *pb.EmptyMsg) (*pb.StatusMsg, error) {
    return &pb.StatusMsg{}, NewCustomError() // NewCustomError implements error and Hater
}

在客户端,我想将收到的

err
转换为
error
接口到
Hater
接口。

_, err = client.ErrorTest(context.Background(), &pb.EmptyMsg{})
    if err != nil {
        fmt.Println(reflect.TypeOf(&err).Elem())

        if h, ok := err.(hater.Hater); ok { //Can't cast to hater.Hater interface
            h.Show()
        }
    }

问题

客户端返回的错误无法投射到

Hater
接口。

if h, ok := err.(hater.Hater); ok { //Can't cast to hater.Hater interface
    h.Show()
}

如何

如何将客户端返回的错误投射到

Hater
接口?

======================================

客户端.go

package main

import (
    "context"
    "fmt"
    pb "main/errortest"
    "main/hater"
    "reflect"

    "google.golang.org/grpc"
    "google.golang.org/grpc/credentials/insecure"
)

func main() {
    conn, err := grpc.Dial("localhost:9090", grpc.WithTransportCredentials(insecure.NewCredentials()))
    if err != nil {
        return
    }
    defer conn.Close()

    client := pb.NewErrorTestClient(conn)

    _, err = client.ErrorTest(context.Background(), &pb.EmptyMsg{})
    if err != nil {
        fmt.Println(reflect.TypeOf(&err).Elem())

        if h, ok := err.(hater.Hater); ok { //Can't cast to hater.Hater interface
            h.Show()
        }
    }
}

服务器.go

package main

import (
    "context"
    "fmt"
    "log"
    "net"

    "google.golang.org/grpc"

    pb "main/errortest"
    "main/hater"
)

type ErrorTestServer struct {
    pb.UnimplementedErrorTestServer
}

func (s ErrorTestServer) ErrorTest(ctx context.Context, _ *pb.EmptyMsg) (*pb.StatusMsg, error) {
    return &pb.StatusMsg{}, NewCustomError()
}

func NewCustomError() hater.CustomError {
    return hater.CustomError{
        Message: "Greetings from Bali!",
    }
}

func main() {
    lis, err := net.Listen("tcp", fmt.Sprintf("localhost:%d", 9090))
    if err != nil {
        log.Fatalf("failed to listen: %v", err)
    }
    var opts []grpc.ServerOption

    grpcServer := grpc.NewServer(opts...)
    pb.RegisterErrorTestServer(grpcServer, ErrorTestServer{})

    if err := grpcServer.Serve(lis); err != nil {
        fmt.Print("failed to start server")
    }
}

自定义错误,实现了 error 和 hater.go 接口

package hater

import "fmt"

type Hater interface {
    Show()
    error
}

type CustomError struct {
    Message string
}

func (e CustomError) Show() {
    fmt.Println(e.Message)
}

func (e CustomError) Error() string {
    return e.Message
}
go grpc
1个回答
1
投票

gRPC
不传输 go error 对象。它传输 gRPC 状态,其中可以包含 gRPC 状态代码 + 错误消息。在客户端上,您收到 gRPC 状态错误,而不是您发送的自定义错误。

最好使用grpc状态错误(或实现接口)在服务器端响应,因此如果发生错误,实际上会出现non-OK gRPC状态。否则 gRPC 状态将始终为

0-OK

如果您想在客户端再次出现自定义错误,您需要找到一种方法从传输的信息中检测它们。例如通过错误消息。然后在客户端重新创建它们,最好在应用于所有 gRPC 调用的中央位置。

如果您想传输自定义错误,则另一个选项是,您必须在响应中执行此操作。另外,在响应中返回自定义错误并为其定义

proto
消息。这样您就可以得到 gRPC 状态错误(报告正确的 gRPC 状态代码)以及响应中的自定义错误。

© www.soinside.com 2019 - 2024. All rights reserved.