【问题标题】:Getting chunked HTTPS response not working获取分块 HTTPS 响应不起作用
【发布时间】:2015-05-05 11:07:36
【问题描述】:

我已经被这个问题困扰了很长时间了。我已经对此进行了谷歌搜索,并且还看到了与 SO 中“分块”相关的所有链接。所以,最后决定发布这个问题。让我简单介绍一下这个问题。我有 Java 代码,它使用套接字从 HTTPS 读取响应。响应被正确接收并且一切正常,除非传输编码被“分块”。我试图从套接字读取分块响应作为字节数组,当我将它转换为字符串时,响应是不可读的。我怀疑我在处理块数据时做错了什么。由于这个问题,当我尝试解压缩响应时,我也会收到“不是 GZip 格式”异常。我用来处理块的代码是

    int chunkLength;

    do {
        String lengthLine = inStream.readLine();
        if (lengthLine == null) {
            return false;
        }
        chunkLength = Integer.parseInt(lengthLine.trim(), 16);
        if (chunkLength > 0) {
            byte[] chunk = new byte[chunkLength];
            int bytesRead = inStream.read(chunk);
            if (bytesRead < chunkLength) {
                return false;
            }
            //Burn a CR/LF
            inStream.readLine();
        }//if chunkLength
    } while (chunkLength > 0) ;
    return true;

由于我刚开始在 SO 中提出问题,因此我可能会遗漏一些(可能很多)细节,这些细节可能需要您提供解决方案。在这种情况下请原谅我,如果您需要更多详细信息,请告诉我。任何帮助将不胜感激。干杯。

【问题讨论】:

  • 为什么?为什么不使用 HttpURLConnection 为您解决所有问题?
  • 感谢您的及时回复。我们应该使用套接字是产品中的一个约束。实际上我们在浏览器中设置代理来记录 HTTP 流量,我们使用套接字读取记录的流量。
  • HttpURLConnection 使用套接字。如果有人设置了一个约束来确定您使用哪些类,那么他们不应该这样做。

标签: java sockets chunked-encoding


【解决方案1】:

我在这段代码中看到了三个问题:

  1. 您没有考虑到各个块可能包含您没有跳过的扩展信息。这并不常见,但它是规范的一部分,因此您应该为其编写代码。否则,如果您遇到 Integer.parseInt() 呼叫,将会失败。

  2. 您没有读取整个块数据。由于您使用的是inStreeam.read(),因此它返回的字节数可能少于请求的字节数。如果发生这种情况,请不要停止阅读,这是套接字的正常行为。您需要循环调用read(),直到完整接收到chunkLength 字节数。只有在报告真正的错误时才停止阅读。

  3. 您没有读取出现在最后一个块之后的尾随 HTTP 标头。即使没有标头,仍然有一个 CRLF 终止符来结束 HTTP 响应。

试试这样的:

try {
    String line;

    do {
        // read the chunk header
        line = inStream.readLine();
        if (line == null) {
            return false;
        }
        // ignore any extensions after the chunk size
        int idx = line.indexOf(';');
        if (idx != -1) {
            line = line.substring(0, idx);
        }
        // parse the chunk size
        int chunkLength = Integer.parseInt(line, 16);
        if (chunkLength < 0) {
            return false;
        }
        // has the last chunk been reached?
        if (chunkLength == 0) {
            break;
        }
        // read the chunk data
        byte[] chunk = new byte[chunkLength];
        int offset = 0;
        do {
            int bytesRead = inStream.read(chunk, offset, chunkLength-offset);
            if (bytesRead < 0) {
                return false;
            }
            offset += bytesRead;
        } while (offset < chunkLength);
        // burn a CRLF at the end of the chunk
        inStream.readLine();
        // now do something with the chunk...
    } while (true);

    // read trailing HTTP headers
    do {
        line = inStream.readLine();
        if (line == null) {
            return false;
        }
        // has the last header been read?
        if (line.isEmpty()) {
            break;
        }
        // process the line as needed...
    } while (true);

    // all done
    return true;
}
catch (Exception e) {
    return false;
}

话虽如此,请记住,分块并不能否定 TCP/HTTP 允许流式传输字节的事实。每个chunk 只是较大数据的一小部分。所以不要尝试将每个单独的chunk 原样转换为字符串,或者尝试将其作为一个完整的单元解压缩。您需要将chunks 收集到您选择的文件/容器中,然后在到达 HTTP 响应的末尾后将整个收集的数据作为一个整体进行处理。除非您将块推送到流处理器中,例如支持推送流的 GZip 解压缩器。如果您确实需要将收集的数据转换为字符串,请确保您使用的是在 HTTP 响应的 Content-Type 标头中指定的 charset(如果没有指定 charset,则使用适当的默认值),因此收集的数据被正确解码为 Java 的原生 UTF-16 字符串编码。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-07-02
    • 2011-05-13
    • 1970-01-01
    • 1970-01-01
    • 2015-10-01
    • 2020-06-18
    • 1970-01-01
    相关资源
    最近更新 更多