Java 从 json 属性解压缩 HTTP GZIP 内容

Java decompress HTTP GZIP content from json attribute

我们正在使用 packetbeat,这是一种网络数据包分析工具,用于捕获 http 请求和 http 响应。 Packebeat 以 json 格式保存此数据包事件。当服务器支持 gzip 压缩时,问题就来了,packetbeat 无法解压内容并直接将 gzip 内容保存为 json 属性。可以看到(注:json已经简化);

{
 {
     ... ,
     "content-type":"application/json;charset=UTF-8",
     "transfer-encoding":"chunked",
     "content-length":6347,
     "x-application-context":"proxy-service:pre,native:8080",
     "content-encoding":"gzip",
     "connection":"keep-alive",
     "date":"Mon, 18 Dec 2017 07:18:23 GMT"
 },
 "body": "\u001f\ufffd\u0008\u0000\u0000\u0000\u0000\u0000\u0000\u0003\ufffd]k\ufffd\u0014DZ\ufffd/\ufffdYI\ufffd#\ufffd*\ufffdo\ufffd\ufffd\ufffd\u0002\t\u0010^\ufffd\u001c\u000eE=\ufffd{\ufffdb\ufffd\ufffdE\ufffd\ufffdC\ufffd\ufffdf\ufffd,\ufffd\u003e\ufffd\ufffd\ufffd\u001ef\u001a\u0008\u0005\ufffd\ufffdg\ufffd\ufffd\ufffdYYU\ufffd\ufffd;\ufffdoN\ufffd\ufffd\ufffdg\ufffd\u0011UdK\ufffd\u0015\u0015\ufffdo\u000eH\ufffd\u000c\u0015Iq\ndC\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd ... "
}

我们正在考虑预处理数据包 json 文件以解压缩内容。有人可以告诉我使用 java 解压缩压缩 "body" json 属性需要什么吗?

在Java中你可以使用GZIPInputStream class来解码GZIP数据,我想你需要先把值变成一个ByteArrayInputStream。

您的数据已不可恢复地损坏。一般来说,我会建议使用 Base64 编码来传输打包到 JSON 中的二进制数据,但如果您喜欢试验,可以在 Binary Data in JSON String. Something better than Base64 中阅读可能的替代方案。

否则,理论上你可以只使用 String.getBytes() 的变体来获取字节数组,并将结果包装到提到的(在另一个答案中)流中:

byte bodyBytes[]=body.getBytes();
ByteArrayInputStream bais=new ByteArrayInputStream(bodyBytes);
GZipInputStream gis=new GZipInputStream(bais);
<do something with gis here, perhaps use an additional DataInputStream>

除了字符串(这通常不是一个好主意)之外,这是解压 gzip 压缩的字节数组的方式。
然而,有效的 gzip 数据以幻数 0x1F、0x8B 开头(再次参见 Wikipedia, or you can also dig up the actual specification). Your data starts with 0x1F (the \u001F part), but continues with a \ufffd Unicode character, which a replacement character (see Wikipedia)。
某些工具正在对二进制数据进行编码并且不喜欢 0x8B,很可能是因为它 >=0x80。如果你进一步阅读你的 JSON,里面有很多 \ufffd-s,所有大于(或等于)0x80 的值都被这个替换了。因此,即使 JSON 内部支持原始二进制数据(但它不支持),目前的数据也无法恢复。