【问题标题】:Unzip http response解压http响应
【发布时间】:2021-03-20 21:29:55
【问题描述】:

Java 初学者,我尝试解压缩 Gzip 格式的 HTTP 响应。粗略地说,我有一个 bufferReader,它允许我从套接字读取 http 响应的行。多亏了这一点,我解析了 http 标头,如果它指定正文是 gzip 格式,那么我必须解压缩它。这是我使用的代码:

DataInputStream response = new DataInputStream(clientSideSocket.getInputStream());
BufferedReader buffer = new BufferedReader(new InputStreamReader(response))

header = parseHTTPHeader(buffer);  // return a map<String,String> with header options

StringBuilder SBresponseBody = new StringBuilder();
String responseBody = new String();
String line;

while((line = buffer.readLine())!= null) // extract the body as if was a string...
    SBresponseBody.append(line);

responseBody = SBresponseBody.toString();

if (header.get("Content-Encoding").contains("gzip"))
    responseBody = unzip(responseBody); // function I try to construct

我对解压功能的尝试如下:

private String unzip(String body) throws IOException {
    String responseBody = "";

    byte[] readBuffer = new byte[5000];
    GZIPInputStream  gzip = new GZIPInputStream (new ByteArrayInputStream(body.getBytes());

    int read = gzip.read(readBuffer,0,readBuffer.length);
    gzip.close();
    
    byte[] result = Arrays.copyOf(readBuffer, read);


    responseBody = new String(result, "UTF-8");

    return responseBody;
}

我在 GZIPInputStream 中收到错误:不是 GZIP 格式(因为在正文中找不到 gzip 标头)。

以下是我的想法:

• body.toByte() 是否错误,因为它已被 bufferReader 作为字符串读取,因此将其转换回 byte[] 没有意义,因为它已经以错误的方式解释?还是我以错误的方式将 Sting 正文重新转换为 byte[]?

• 我是否必须使用 HTTP 标头中提供的信息自己构建 GZIP 标头并将其添加到字符串正文?

• 我是否需要从我的 socket.getInputStream() 创建另一个 InputStream 来逐字节读取信息,还是因为已经有一个缓冲区“连接”到此套接字而变得棘手?

【问题讨论】:

标签: java http gzip unzip


【解决方案1】:

大致来说,我有一个 bufferReader,它允许我从套接字读取 http 响应的行。

您已经手动处理了一个 HTTP 客户端。

这不是一件好事; HTTP 比您想象的要复杂得多。 gzip 只是您需要考虑的大约 10,000 件事情之一。有 HTTP/2.0、Spdy、http3、分块传输编码、TLS、重定向、mime 打包等等。

所以,如果你想编写一个实际的 HTTP 客户端,你需要大约 100 倍的代码和大量的领域知识,因为 HTTP 协议的实际规范虽然很方便,但并不能真正说明问题。您正在实施的事实上的协议是“连接到互联网的服务器倾向于发送的任何内容”,并且它们倾向于发送的内容与“常用的浏览器倾向于正确的内容”紧密相关,这几乎是,但不完全是,该规范文件所说的。这是语用学和实现是“真正的规范”的情况之一,而实际的规范只是试图记录现实。

这是一个很长的路要走:您的错误是尝试手动处理 HTTP 客户端。不要那样做。在核心库中使用jdk11中引入的OkHttphttp client

但是,我知道我想要什么!

不过,您的代码充满了错误。

DataInputStream 响应 = new DataInputStream(clientSideSocket.getInputStream());

DataInputStream 在这里没用。删除该包装。

BufferedReader buffer = new BufferedReader(new InputStreamReader(response))

缺少分号。此外,这已损坏 - 这将使用“平台默认编码”将流经线路的字节转换为字符,这是错误的,您需要查看 Content-Type 标头。

responseBody = 解压缩(responseBody)

你不能这样做。您的主要误解是您似乎认为一堆字节和一系列字符之间没有区别。

错了。一旦将字节存储到字符中,您就无法再解压缩了

解决方法是检查 gzip 标头FIRST,然后通过 GZipStream 包装您的输入流。

【讨论】:

    猜你喜欢
    • 2020-11-13
    • 1970-01-01
    • 2012-02-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-02
    • 1970-01-01
    相关资源
    最近更新 更多