代码之家  ›  专栏  ›  技术社区  ›  Paul Richter

GZIPInputStream-损坏的GZIP尾部

  •  2
  • Paul Richter  · 技术社区  · 11 年前

    我有一个静态助手方法负责获取 压缩的JSON字符串 从我们的Rails应用程序,并在返回 String 代表。

    我写了两个JUnit测试,一个测试JSON是否正确解析,另一个更基本的测试确定是否从服务器返回长度大于零的字符串。

    问题是: 当我运行测试套件时,第一个测试方法正确地成功了,而另一个则失败了 IOException 以及消息“损坏的GZIP尾部”(请参阅下面的代码)。我已经确定,失败的不是测试本身,因为当我使测试以相反的顺序运行时,“成功”的测试会被逆转(换句话说,无论怎样,总是第二个测试失败,无论两个测试中的哪一个是第二个运行)。

    这是helper方法:

    public static String doHTTPGet(String urlString) throws IOException{
        URL weatherAPI = new URL(urlString);
        HttpURLConnection apiConnection = (HttpURLConnection) weatherAPI.openConnection();
        apiConnection.setRequestMethod("GET");
        apiConnection.setRequestProperty("Accept-Encoding", "gzip");
    
        apiConnection.connect();
    
        BufferedInputStream bufferedInputStream = new BufferedInputStream(apiConnection.getInputStream());
        byte[] inputByteBuffer = new byte[10 * 1024];
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream(10 * 1024); // initialize the output stream with at least one buffer's worth of bytes
        while(bufferedInputStream.read(inputByteBuffer)  > -1){
            outputStream.write(inputByteBuffer);
        }
    
        outputStream.close();
        bufferedInputStream.close();
        apiConnection.disconnect();
    
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(outputStream.toByteArray());
        byteArrayInputStream.close();
    
        GZIPInputStream gis = new GZIPInputStream(byteArrayInputStream);
        InputStreamReader inputStreamReader = new InputStreamReader(gis, "UTF-8");
        BufferedReader reader = new BufferedReader(inputStreamReader);
    
        String decompressedResponse = "";
        String line;
    
        // readLine() is generating the IOException on the second pass.
        while((line = reader.readLine()) != null){
            decompressedResponse += line;
        }
    
        reader.close();
        inputStreamReader.close();
        gis.close();
    
        return decompressedResponse;
    }
    

    错误发生在helper方法的底部,在线上 while((line = reader.readLine()) != null)... 。具体而言,错误发生在 reader.readLine() .

    以及两种测试方法:

    @Test
    public void testHttpGet(){
        try {
            // FILTERED_API_URL_WITH_TOKEN is merely the URL with an auth token
            String apiResponse = HTTPHelper.doHTTPGet(GlobalConstants.FILTERED_API_URL_WITH_TOKEN);
            assertNotNull(apiResponse);
            assertTrue("The size of the API response should be greater than zero. It is an empty string.", apiResponse.length() > 0);
        } catch (IOException e) {
            e.printStackTrace();
            assertTrue("An exception occured while trying to perform the HTTP Get to the api at URL " + GlobalConstants.FILTERED_API_URL_WITH_TOKEN, false);
        }
    }
    
    @Test
    public void testAPIContent(){
        try {
            // the getAPIJson() method basically does the same as the testHttpGet
            // method, but converts the string to a json
            JSONObject jsonObject = XMLProducerFromAPI.getAPIJson();
            System.out.println(jsonObject);
            assertNotNull(jsonObject);
        } catch (IOException e) {
            e.printStackTrace();
            assertTrue("An IOException occured. See stack trace", false);
        } catch (JSONException e) {
            e.printStackTrace();
            assertTrue("A JSONException occured. See stack trace", false);
        }
    }
    

    我已经通读了 this question the answer ,但我不相信它适用,(或者可能是这样,我误解了,如果是这样的话,请告诉我),我尝试了他们的方法,但只收到了同样的信息。

    作为 doHTTPGet 方法是静态的,并且创建的对象是在方法的主体内完成的,所以不应该重用任何东西(流、连接对象等)。坦率地说,我被难住了。

    问题: 我是否在助手代码中做错了什么,或者误解了某个对象的某些用法,从而导致“损坏的GZIP尾部”消息?简而言之,在我的场景中,是什么导致了这个错误?

    和往常一样,如果我在这个问题上遗漏了什么,请告诉我。

    编辑

    这是堆栈跟踪:

    java.io.IOException: Corrupt GZIP trailer
        at java.util.zip.GZIPInputStream.readTrailer(GZIPInputStream.java:200)
        at java.util.zip.GZIPInputStream.read(GZIPInputStream.java:92)
        at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:264)
        at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:306)
        at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:158)
        at java.io.InputStreamReader.read(InputStreamReader.java:167)
        at java.io.BufferedReader.fill(BufferedReader.java:136)
        at java.io.BufferedReader.readLine(BufferedReader.java:299)
        at java.io.BufferedReader.readLine(BufferedReader.java:362)
        at com.weathertx.xmlserver.support.HTTPHelper.doHTTPGet(HTTPHelper.java:60)
        at com.weathertx.xmlserver.tests.HttpHelperTest.getAPIResponse(HttpHelperTest.java:47)
        at com.weathertx.xmlserver.tests.HttpHelperTest.testHttpGet(HttpHelperTest.java:21)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
        at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
        at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
        at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
        at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
        at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
        at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
        at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
        at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
        at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
        at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
        at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
        at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
        at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
        at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
    
    1 回复  |  直到 7 年前
        1
  •  0
  •   Community Dan Abramov    7 年前

    问题已经解决。坦率地说,我不太明白为什么它最初不起作用,或者它有什么问题(除了明显过于复杂和不必要的复杂之外)。幸亏 this solution ,不知何故,我错过了第一次搜索,我能够通过基本上完全实现他们所做的来解决问题。这是我的最后一个代码:

    public static String doHTTPGet(String urlString) throws IOException{
        URL weatherAPI = new URL(urlString);
        HttpURLConnection apiConnection = (HttpURLConnection) weatherAPI.openConnection();
        apiConnection.setRequestMethod("GET");
        apiConnection.setRequestProperty("Accept-Encoding", "gzip");
    
        apiConnection.connect();
    
        InputStream gzippedResponse = apiConnection.getInputStream();
        InputStream decompressedResponse = new GZIPInputStream(gzippedResponse);
        Reader reader = new InputStreamReader(decompressedResponse, "UTF-8");
        StringWriter writer = new StringWriter();
    
        char[] buffer = new char[10240];
        for(int length = 0; (length = reader.read(buffer)) > 0;){
            writer.write(buffer, 0, length);
        }
    
        writer.close();
        reader.close();
        decompressedResponse.close();
        gzippedResponse.close();
        apiConnection.disconnect();
    
        return writer.toString();
    }
    

    因此,最终,我不需要通过字节数组流和所有地方传递数据。除了我最初的方法令人费解之外,如果有人知道我最初的算法产生“损坏的GZIP尾部”错误消息的具体原因的话 之后 无论如何,这个方法的第一次调用都要让我知道。