理想情况下,您应该使用高级库来为您处理这些东西。这样,每当发布新版本的HTTP时,库维护者都希望为您完成所有艰苦的工作,您只需要更新版本的库。
除此之外,尝试自己做是一个很好的练习。
假设您正在从 TCP 套接字以字节流的形式读取 HTTP 响应。如果没有 gzip 编码,则将整个响应放入 String 中可能会起作用。但是,“内容编码:gzip”标头的存在意味着响应正文(如您所见)是二进制的。
您可以将响应正文的开头标识为字符串序列“\r\n\r\n”第一次出现之后的第一个字节(或0x0d、0x0a、0x0d 0x0a 4 个字节)。
gzip 编码有一个特殊的标头,您应该为此测试前 3 个正文字节:
byte[] buf; // from the HTTP Response stream
// ... insert code here to populate buf from HTTP Response stream
// ...
int bodyLen = 1234; // populate this value from 'Content-length' header
int bodyStart = 123; // index of byte buffer where body starts
if (bodyLen > 4 && buf[bodyStart] == 0x1f && buf[bodyStart + 1] == (byte) 0x8b && buf[bodyStart + 2] == 0x08) {
// gzip compressed body
ByteArrayInputStream bais = new ByteArrayInputStream(buf);
if (bodyStart > 0) bais.skip(bodyStart);
// Decompress the bytes
byte[] decompressedBytes = new byte[bodyLen * 4];
int decompressedDataLength = 0;
try {
// note: replace this try-catch with try-with-resources here where possible
GZIPInputStream gzis = new GZIPInputStream(bais);
decompressedDataLength = gzis.read(decompressedBytes);
gzis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
如果前 3 个字节与神奇的 GZIP 标头值不匹配,则 GZIPInputStream 会生成“不采用 GZIP 格式”错误,因此测试这些值将有助于解决您的特定问题。
GZIP格式中还有一个CRC校验和,但是如果缺少或不正确,您应该会看到不同的错误。