我通过执行以下操作发送和接收HTTP post请求:
FooJson fooJson = new FooJson();
fooJson.setName("Bob");
FooProto.Builder fooProto = FooProto.newBuilder(); // google protobuf
fooProto.setColor("Blue");
fooProto.setLength(30);
BarProto.Builder barProto = BarProto.newBuilder();
barProto.setWeight(65);
fooProto.setBarProto(barProto);
barJson.setFooProto(new String(fooProto.build().toByteArray()));
List<BarJson> barJsonList = new ArrayList<BarJson>();
barJsonList.add(barJson);
fooJson.setBarJsonList(barJsonList);
String data = writeJson(fooJson); // wrapper for jackson JsonGenerator
RequestEntity re = new ByteArrayRequestEntity(data.getBytes());
PostMethod method = new PostMethod("http://foo.net:123/path");
method.setRequestEntity(re);
httpClient.executeMethod(method);
在接收端,我解析以下内容:
FooJson fooJson = readJson(request.getInputStream(), FooJson.class);
for (BarJson barJson : fooJson.getBarJsonList()) {
FooProto fooProto = FooProto.parseFrom(barJson.getFooProto().getBytes());
}
解析接收端协议缓冲区时的结果是:
com.google.protobuf.InvalidProtocolBufferException: While parsing a protocol message, the input ended unexpectedly in the middle of a field. This could mean either than the input has been truncated or that an embedded message misreported its own length.
我是否在将协议缓冲区转换为字符串的方式出错?我怎么能解决这个问题?
答案 0 :(得分:3)
我怀疑你可以通过JSON可靠地隧道运行protobuf(其有效载荷是纯二进制,而不是文本),而无需进行某种类型的编码,如base64或十六进制编码。将protobuf有效负载从字节转换为base64文本。然后在接收端将它从base64文本转换回二进制文件。
您将获得protobuf异常,因为接收端的字节数组与您发送的protobuf有效负载不匹配。当您转换为字符串并返回而不使用某种类型的编码时,数据会被释放。
我对javax.xml.bind.DatatypeConverter运气不错。它是Java 1.6的一部分。在发送端使用printBase64Binary,在接收端使用parseBase64Binary。
[更新]
或者,如果base64过于丑陋,您可以使用protobuf-java-format将protobuf对象序列化为多种不同的字符串格式(JSON,XML)。这可能看起来有点奇怪,因为barJson.setFooProto将包含一个本身就是JSON有效负载的字符串。会有很多转义的引号字符 - 但它应该有效。
答案 1 :(得分:0)
你的错误在这里:
barJson.setFooProto(new String(fooProto.build().toByteArray()));
不要尝试从任意二进制数据创建一个字符串 - 这很可能会破坏数据,具体取决于使用的编码;特别是使用JSON,UTF-8编码几乎可以保证损坏(UTF-8中不允许使用某些字节序列,因此您要么获得异常,要么数据会发生变异)。
相反,将字段定义为byte[]
,让杰克逊使用Base64编码。这是正确的,并且相对有效地完成。
您可能还想考虑仅使用JSON来完成整个事情,如第一个答案所示。无需使用特定的Protobuf风味;如果你真的需要它们,你总是可以单独构造PB对象。