如何让gRPC Gateway返回Protobuf格式的REST响应?
问题描述
原有REST API采用Protobuf格式(application/x-protobuf)交互,迁移到gRPC Gateway后,默认返回JSON格式(application/json)响应,调用/test接口时无法获取预期的Protobuf格式返回结果,需要配置gRPC Gateway支持返回Protobuf格式响应。
服务契约定义如下:
service TestService { rpc GetBattleStatusByEntityIds(ProtoRequest) returns (ProtoResponse) { option (google.api.http) = { get : "/test" }; } }
解决方案
gRPC Gateway支持通过自定义编解码器(Marshaller)替换默认的JSON处理逻辑,以此实现返回Protobuf格式响应。具体实现如下:
1. 实现Protobuf格式编解码器
编写符合runtime.Marshaller接口的Protobuf处理结构体,负责消息的序列化和反序列化:
import ( "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" "google.golang.org/protobuf/proto" ) type protoMarshaller struct{} // Marshal 将Protobuf消息序列化为二进制数据 func (protoMarshaller) Marshal(v interface{}) ([]byte, error) { msg, ok := v.(proto.Message) if !ok { return nil, runtime.ErrInvalidMessageType } return proto.Marshal(msg) } // Unmarshal 将二进制数据反序列化为Protobuf消息 func (protoMarshaller) Unmarshal(data []byte, v interface{}) error { msg, ok := v.(proto.Message) if !ok { return runtime.ErrInvalidMessageType } return proto.Unmarshal(data, msg) } // ContentType 返回Protobuf对应的Content-Type func (protoMarshaller) ContentType(_ interface{}) string { return "application/x-protobuf" }
2. 注册编解码器到Gateway实例
在初始化gRPC Gateway的ServeMux时,注册自定义的Protobuf编解码器。如果需要默认返回Protobuf,就用runtime.MIMEWildcard;如果要同时支持JSON和Protobuf,可同时注册两种编解码器,Gateway会根据请求的Accept头自动适配:
import ( "context" "net/http" "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" "google.golang.org/grpc" ) func main() { ctx := context.Background() ctx, cancel := context.WithCancel(ctx) defer cancel() // 初始化ServeMux,注册自定义编解码器 mux := runtime.NewServeMux( // 设置默认编解码器为Protobuf runtime.WithMarshalerOption(runtime.MIMEWildcard, &protoMarshaller{}), // 若需同时支持JSON,取消下方注释 // runtime.WithMarshalerOption(runtime.MIMEJSON, &runtime.JSONPb{}), ) // 注册gRPC服务到Gateway,替换为你的gRPC服务地址 dialOpts := []grpc.DialOption{grpc.WithInsecure()} if err := RegisterTestServiceHandlerFromEndpoint(ctx, mux, "grpc-server:50051", dialOpts); err != nil { panic(err) } // 启动HTTP服务 if err := http.ListenAndServe(":8080", mux); err != nil { panic(err) } }
3. 测试验证
- 若设置了默认Protobuf编解码器,直接调用
/test接口会返回application/x-protobuf格式的响应 - 若同时注册了JSON编解码器,可通过请求头
Accept: application/x-protobuf指定获取Protobuf格式,Accept: application/json获取JSON格式
内容的提问来源于stack exchange,提问作者MOHAMMAD ARSHAD
相关产品推荐
相关产品推荐

