什么
我想通过 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
}
gRPC
不传输 go error 对象。它传输 gRPC 状态,其中可以包含 gRPC 状态代码 + 错误消息。在客户端上,您收到 gRPC 状态错误,而不是您发送的自定义错误。
最好使用grpc状态错误(或实现接口)在服务器端响应,因此如果发生错误,实际上会出现non-OK gRPC状态。否则 gRPC 状态将始终为
0-OK
。
如果您想在客户端再次出现自定义错误,您需要找到一种方法从传输的信息中检测它们。例如通过错误消息。然后在客户端重新创建它们,最好在应用于所有 gRPC 调用的中央位置。
如果您想传输自定义错误,则另一个选项是,您必须在响应中执行此操作。另外,在响应中返回自定义错误并为其定义
proto
消息。这样您就可以得到 gRPC 状态错误(报告正确的 gRPC 状态代码)以及响应中的自定义错误。