2013-10-12 33 views
1

我有一個靜態幫助程序方法負責從我們的Rails應用程序獲取壓縮的JSON字符串,並在返回String表示之前解壓縮數據。GZIPInputStream - 損壞的GZIP預告片

我寫了兩個JUnit測試,一個測試JSON正確解析,另一個測試是否從服務器返回長度大於零的字符串。

問題:當運行測試套件,第一測試方法成功正確,另失敗並IOException和消息「損壞GZIP預告片」(參見下面的代碼)。我已經確定,這不是測試本身的失敗,因爲當我導致測試以相反順序運行時,「成功」測試被逆轉(換句話說,無論如何,它總是第二次測試失敗,不管這兩個測試中的哪一個運行在第二個)。

這是輔助方法:

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; 
} 

朝向輔助方法的底將出現錯誤,就行了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 questionthe answer閱讀,但我不相信它的適用,(或者也許是我誤會了,讓我知道,如果是這樣的案件),我嘗試了他們的方法,只收到相同的信息。

由於doHTTPGet方法是靜態的,所創建的對象在方法體內完成,因此應該重用任何內容(流,連接對象等)。坦率地說,我很難過。

問題:我在助手代碼中做了什麼錯誤,或者我誤解了某些對象的使用,會產生「Corrupt GZIP Trailer」消息?總之,在我的情況下會導致這種錯誤?

一如既往,請讓我知道,如果我沒有離開這個問題的任何東西。

編輯

這是堆棧跟蹤:

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) 
+0

另外,令人遺憾的是,有問題的API受IP限制,所以不幸的是,我不能在不知道每個人的IP的情況下訪問。 –

回答

0

問題已解決。坦率地說,我不太明白爲什麼它原來不起作用,或者它有什麼問題(除了顯然過於複雜和不必要的複雜外)。感謝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預告片」錯誤信息這個方法的第一次調用,通過一切手段讓我知道。

+1

比較write()調用。這一個是正確的,使用讀取計數。 – EJP

+0

@EJP因此,我的原始版本每次都會不斷地寫10240字節,而且這個版本可以讀取多達10240個字節,這意味着最後一次讀取的字節數可能會少於一個字節(正確?)。但是,在流和連接等全部關閉之後,當第二次調用該方法時,打開新的流和連接。還有剩下的垃圾可以通過,或者有什麼影響? –

+0

您正在寫最後一次寫入的垃圾,並且您正在收到一條消息,內容正是如此。這很清楚。 – EJP