
关于 http 请求 grpc-gateway stream 流式响应时无法解码返回值
问题:
使用 grpc-gateway 进行 http 请求时的流式响应,使用 runtime.jsonpb.decode 时,得到的返回值都是 nil。
解决:
根据推测,该问题可能有以下几个原因造成:
- grpc-gateway 版本过低:请升级至 grpc-ecosystem/grpc-gateway/v2 v2.4.0。
- 返回结果中存在多余字段:grpc-gateway 返回的结果中包含了一个额外的 result 字段。请在 proto 文件中添加以下代码:
// 新增
message httpresp {
resp result = 1;
}- 解码时未使用正确类型:在解码时,请使用 *pb.httpresp 而不是 *pb.resp。
单元测试:
更新代码如下:
package main
import (
"bytes"
"net/http"
"test/pb"
"testing"
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"google.golang.org/grpc"
)
func testhttprespstream(t *testing.t) {
url := "http://127.0.0.1:8080/query-stream-resp"
reqdata := &pb.req{id: 1, name: "111"}
var buffer bytes.buffer
encoder := (&runtime.jsonpb{}).newencoder(&buffer)
if err := encoder.encode(reqdata); err != nil {
t.fatal(err)
}
ctx, cancel := context.withcancel(context.background())
defer cancel()
req, err := http.newrequestwithcontext(ctx, http.methodpost, url, &buffer)
if err != nil {
t.fatal(err)
}
resp, err := http.defaultclient.do(req)
if err != nil {
t.fatal(err)
}
defer resp.body.close()
jsonb := new(runtime.jsonpb)
dencoder := jsonb.newdecoder(resp.body)
for {
var result *pb.httpresp // 注意 不要使用 *pb.resp
err := dencoder.decode(&result) // &result
if err == nil {
t.logf("resp: %+v", result)
} else {
t.logf("%+v", err)
break
}
}
}更新 proto 文件如下:
syntax = "proto3";
package pb;
option go_package = "/pb;pb";
import "google/api/annotations.proto";
message Req {
int32 id = 1;
string name = 2;
}
message Resp {
int32 code = 1;
string msg = 2;
}
// 新增
message HttpResp {
Resp result = 1;
}
service TestService {
rpc QueryStreamResp(Req) returns (stream HttpResp){
option (google.api.http) = {
post: "/query-stream-resp"
body: "*"
};
};
rpc QueryStreamReq(stream Req) returns (Resp){
option (google.api.http) = {
post: "/query-stream-req"
body: "*"
};
};
rpc Query(stream Req) returns (stream Resp){
option (google.api.http) = {
post: "/query"
body: "*"
};
};
}更新后,单元测试将能够正确解码流式响应。










