Java 获取分块的HTTPS响应不起作用

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

我已经被这个问题困扰了很长时间了。关于这一点,我在谷歌上搜索过,还看到了SO中与“chunked”相关的所有链接。所以,最后决定发布这个问题。让我简单介绍一下这个问题。我有一个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;
int-chunkLength;
做{
String lengthLine=inStream.readLine();
if(lengthLine==null){
返回false;
}
chunkLength=Integer.parseInt(lengthLine.trim(),16);
如果(chunkLength>0){
byte[]chunk=新字节[chunkLength];
int bytesRead=inStream.read(块);
if(字节读取<块长度){
返回false;
}
//燃烧一个CR/LF
inStream.readLine();
}//如果块长度
}而(chunkLength>0);
返回true;

因为我是新来提问的,所以我可能遗漏了一些(可能很多)细节,这些细节可能是你们给出解决方案所需要的。请原谅我在这种情况下,让我知道,如果你需要更多的细节。任何帮助都将不胜感激。干杯。

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

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

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

  • 您没有读取最后一个区块之后出现的后续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;
    }
    
    试试看{
    弦线;
    做{
    //读取块头
    line=inStream.readLine();
    如果(行==null){
    返回false;
    }
    //忽略块大小之后的任何扩展
    int idx=line.indexOf(“;”);
    如果(idx!=-1){
    line=line.子字符串(0,idx);
    }
    //解析块大小
    int chunkLength=Integer.parseInt(第16行);
    if(chunkLength<0){
    返回false;
    }
    //到达最后一块了吗?
    如果(chunkLength==0){
    打破
    }
    //读取区块数据
    byte[]chunk=新字节[chunkLength];
    整数偏移=0;
    做{
    int bytesRead=inStream.read(chunk,offset,chunkLength offset);
    如果(字节读取<0){
    返回false;
    }
    偏移量+=字节读取;
    }而(偏移量<长度);
    //在块的末尾烧掉一个CRLF
    inStream.readLine();
    //现在对区块做点什么。。。
    }虽然(正确);
    //读取尾部HTTP头
    做{
    line=inStream.readLine();
    如果(行==null){
    返回false;
    }
    //是否已读取最后一个标题?
    if(line.isEmpty()){
    打破
    }
    //根据需要处理生产线。。。
    }虽然(正确);
    //全部完成
    返回true;
    }
    捕获(例外e){
    返回false;
    }
    

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

    为什么?为什么不使用
    HttpURLConnection
    呢?谢谢您的及时回复。我们应该使用套接字,这是产品中的一个限制。实际上,我们正在浏览器中设置代理来记录HTTP流量,并使用套接字读取记录的流量。
    HttpURLConnection
    使用套接字。如果有人正在设置一个约束来确定您使用的类,那么它们不应该是。