使用“Range”标头时,无法让Java的GZIPInputStream从服务器读取“gzip”响应

时间:2013-09-13 15:06:30

标签: java http gzipinputstream http-range

我已经使用了一段时间来从网络服务器上获取数据的一些代码,几个月前,我添加了压缩支持,这似乎适用于“常规”HTTP响应,其中整个文件包含在回复中。但是,当我使用Range标题时,它似乎不起作用。

以下是执行实际工作的代码:

    InputStream in = null;

    int bufferSize = 4096;

    int responseCode = conn.getResponseCode();

    boolean error = 5 == responseCode / 100
        || 4 == responseCode / 100;

    int bytesRead = 0;

    try
    {
        if(error)
            in = conn.getErrorStream();
        else
            in = conn.getInputStream();

        // Buffer the input
        in = new BufferedInputStream(in);

        // Handle compressed responses
        if("gzip".equalsIgnoreCase(conn.getHeaderField("Content-Encoding")))
            in = new GZIPInputStream(in);
        else if("deflate".equalsIgnoreCase(conn.getHeaderField("Content-Encoding")))
            in = new InflaterInputStream(in, new Inflater(true));

        int n;
        byte[] buffer = new byte[bufferSize];

        // Now, just write out all the bytes
        while(-1 != (n = in.read(buffer)))
        {
            bytesRead += n;
            out.write(buffer, 0, n);
        }
    }
    catch (IOException ioe)
    {
        System.err.println("Got IOException after reading " + bytesRead + " bytes");
        throw ioe;
    }
    finally
    {
        if(null != in) try { in.close(); }
        catch (IOException ioe)
        {
            System.err.println("Could not close InputStream");
            ioe.printStackTrace();
        }
    }

点击带有标题Accept-Encoding: gzip,deflate,identity的URL效果很好:我可以看到服务器以压缩格式返回数据,上面的代码很好地解压缩了。

如果我然后添加Range: bytes=0-50标头,我会收到以下异常:

Got IOException after reading 0 bytes
Exception in thread "main" java.io.EOFException: Unexpected end of ZLIB input stream
at java.util.zip.InflaterInputStream.fill(InflaterInputStream.java:240)
at java.util.zip.InflaterInputStream.read(InflaterInputStream.java:158)
at java.util.zip.GZIPInputStream.read(GZIPInputStream.java:116)
at java.io.FilterInputStream.read(FilterInputStream.java:107)
at [my code]([my code]:511)

我的代码中的行511是包含in.read()调用的行。响应包括以下标题:

Content-Type: text/html
Content-Encoding: gzip
Content-Range: bytes 0-50/751
Content-Length: 51

我已经验证过,如果我不尝试解压缩响应,我实际上在响应中得到51个字节......这不是服务器故障(至少我可以告诉)。我的服务器(Apache httpd)不支持“deflate”,所以我无法测试另一种压缩方案(至少现在不行)。

我还试图请求更多的数据(比如目标资源中总共751个字节的700个字节),我得到了同样的错误。

我有什么遗失的吗?

更新 对不起,我忘了在Linux上使用Apache / 2.2.22。没有任何我知道的服务器错误。我在验证从服务器检索的压缩字节时会遇到一些麻烦,因为“gzip”内容编码非常简单......例如我相信我不能只在命令行上使用“gunzip”来解压缩这些字节。不过我会尝试一下。

2 个答案:

答案 0 :(得分:1)

您可以使用'gunzip'对其进行解压缩,请记住,前50个字节可能不足以让gzip解压缩任何内容(标题,字典等)。试试这个:wget -O- -q <URL> | head -c 50 | zcat和你的网址,看看普通的gzip是否适用于代码失败的地方。

答案 1 :(得分:0)

叹息切换到另一台服务器(恰好运行Apache / 2.2.25)表明我的代码实际上工作正常。原始目标服务器似乎受到AWS在US-EAST可用区中当前中断的影响。我将把这一点归结为网络错误并关闭这个问题。感谢那些提出建议的人。