grpc 无法像 http 那也直接把未知对象赋值给 interface 的引用,需要解析为pb定义的具体结构,可以用 google/protobuf/struct.proto 中的 struct 接收 object 类型,然后在golang里面进行解析,代码如下。
可以用于解决一个字段接收或发送多种对象。
效果:
实现转化 pbStruct.struct request.Filter -> golang Struct -> pbStruct.struct response.Data
proto定义:
syntax = "proto3";
import "google/api/annotations.proto";
import "google/protobuf/struct.proto";
message StringMessage {
string type = 1;
google.protobuf.Struct filter = 2;
}
message ListAttrValueReq{
string attr = 1;
string keyword = 2;
}
message Parent{
string type = 1 ;
string id = 2;
}
message User {
string name = 1;
int64 age = 2;
}
message StringResp {
google.protobuf.Struct data = 2;
}
service EchoService {
rpc Echo(StringMessage) returns (StringResp) {
option (google.api.http) = {
post: "/v1/echo"
body: "*"
};
}
}
server代码:
package main
import (
"encoding/json"
"fmt"
pbstruct "github.com/golang/protobuf/ptypes/struct"
"golang.org/x/net/context"
"google.golang.org/grpc"
pb "grpc-learn/proto"
"log"
"net"
)
const (
port = ":51001"
)
type server struct {
}
type User struct {
Name string
Age int
}
func (s *server) Echo(c context.Context, req *pb.StringMessage) (*pb.StringResp, error) {
resp := &pb.StringResp{}
data := &pb.ListAttrValueReq{}
PbStructToInterface(req.Filter, &data)
InterfaceToPbStruct(data, &resp.Data)
fmt.Println(resp.Data)
return resp, nil
}
func PbStructToInterface(source *pbstruct.Struct, result interface{}) error {
bytes, err := source.MarshalJSON()
if err != nil {
return err
}
if err = json.Unmarshal(bytes, &result); err != nil {
return err
}
return nil
}
func InterfaceToPbStruct(source interface{}, result **pbstruct.Struct) error {
marshal, err := json.Marshal(source)
if err != nil {
return err
}
if err = json.Unmarshal(marshal, &result); err != nil {
return err
}
fmt.Println(result)
return nil
}
func main() {
lis, err := net.Listen("tcp", port)
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
// Creates a new gRPC server
s := grpc.NewServer()
pb.RegisterEchoServiceServer(s, &server{})
s.Serve(lis)
}
getway代码:
package main
import (
"flag"
"log"
"net/http"
"github.com/golang/glog"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"golang.org/x/net/context"
"google.golang.org/grpc"
gw "grpc-learn/proto"
)
var (
echoEndpoint = flag.String("echo_endpoint", "localhost:51001", "endpoint of Gateway")
)
func run() error {
ctx := context.Background()
ctx, cancel := context.WithCancel(ctx)
defer cancel()
mux := runtime.NewServeMux()
opts := []grpc.DialOption{grpc.WithInsecure()}
err := gw.RegisterEchoServiceHandlerFromEndpoint(ctx, mux, *echoEndpoint, opts)
if err != nil {
return err
}
log.Println("服务开启")
return http.ListenAndServe(":8080", mux)
}
func main() {
flag.Parse()
defer glog.Flush()
if err := run(); err != nil {
glog.Fatal(err)
}
}