协议缓冲区无法解析具有多个大型消息的单个codeInputStream

时间:2014-09-24 06:07:04

标签: java android protocol-buffers

以下是邮件架构:>

message ServerResponse {
optional string ReferenceCode = 1;
optional NestedMessageProto.NestedMessage NestedMessage = 2;//Huge size data in response
optional bool Success = 3 [default = false];
repeated Errors Errors = 4;
}

下面是从服务器获取响应并调用proto响应方法的代码。

 String apiResponse = Server Response
    protoResponseClass.parseFrom(apiResponse.getBytes())

its failing when reading the NestedMessage  response on below bold line

    public int pushLimit(int byteLimit) throws InvalidProtocolBufferException {
    if (byteLimit < 0) {
        throw InvalidProtocolBufferException.negativeSize();
    }
    byteLimit += totalBytesRetired + bufferPos;
    if (byteLimit > currentLimit) {
        currentLimit = byteLimit + currentLimit;
    }
    final int oldLimit = currentLimit;
    **if (byteLimit > oldLimit) {
        throw InvalidProtocolBufferException.truncatedMessage();
    }**
    currentLimit = byteLimit;
    recomputeBufferSizeAfterLimit();
    return oldLimit;
}

当它读取嵌套消息时,字节限制变得大于旧限制。 可能是什么解决方案?

由于

2 个答案:

答案 0 :(得分:1)

这几乎肯定是问题所在:

String apiResponse = Server Response
protoResponseClass.parseFrom(apiResponse.getBytes())

协议缓冲区消息是二进制数据。它们不是文本,也不应该作为文本处理。您从服务器获取二进制响应,以某种方式将其解释为文本(我们无法告诉您如何),然后使用平台默认编码将其转换回字节数组(几乎总是如此)糟糕的主意 - 即使在调用getBytes() 适当的时候也不要在没有指定字符集的情况下调用getBytes(),这不是在这里。转换为文本和返回几乎肯定会丢失信息 - 很可能使解析代码期望的数据多于消息中实际存在的数据。

您应该从一开始就将服务器响应作为二进制数据处理 - 理想情况下只需将InputStream从服务器响应传递到parseFrom,但至少将其读取为一个字节数组而不是String

答案 1 :(得分:0)

不是将httpresponse转换为字符串然后转换为字节数组进行解析,而是直接使用EntityUtils.toByteArray。

private String readResponse(HttpResponse httpresponse) throws IOException {
        int responseCode = httpresponse.getStatusLine().getStatusCode();
        String mimeType = httpresponse.getFirstHeader(CONTENT_TYPE_KEY).getValue();
        if (responseCode != HttpURLConnection.HTTP_OK) {
            String cause = String.format("Bad HTTP response code: %d\nOr MIME type: %s", responseCode, mimeType);
            throw new IOException(cause);
        }
        return EntityUtils.toString(httpresponse.getEntity());
    }