膨胀gzip HTTP响应正文时,获取“过早耗尽源代码”

时间:2018-08-29 20:51:12

标签: android gzip okhttp okhttp3 okio

当我尝试使用okhttp进行HTTP调用时,出现以下错误:

W/System.err: java.io.EOFException: source exhausted prematurely
W/System.err:     at okio.InflaterSource.read(InflaterSource.java:83)
W/System.err:     at okio.GzipSource.read(GzipSource.java:80)
W/System.err:     at okio.Buffer.writeAll(Buffer.java:1135)
W/System.err:     at okio.RealBufferedSource.readString(RealBufferedSource.java:199)
W/System.err:     at okhttp3.ResponseBody.string(ResponseBody.java:176)
W/System.err:     at com.ethanwang.andplay.OKHttpTaskTag.doInBackground(OKHttpTaskTag.java:41)
W/System.err:     at com.ethanwang.andplay.OKHttpTaskTag.doInBackground(OKHttpTaskTag.java:20)
W/System.err:     at android.os.AsyncTask$2.call(AsyncTask.java:295)
W/System.err:     at java.util.concurrent.FutureTask.run(FutureTask.java:237)
W/System.err:     at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:234)
W/System.err:     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
W/System.err:     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
W/System.err:     at java.lang.Thread.run(Thread.java:818)

我只能找到以下相关问题:https://github.com/square/okhttp/issues/2193,但是我已经确保Content-Length是响应正文的正确长度。这是我记录的okhttp请求和响应:

请求:

    I/System.out: INFO: Sending request http://test.essaybot.com/msg/tag_search on Connection{test.essaybot.com:80, proxy=DIRECT@ hostAddress=test.essaybot.com/34.208.145.50:80 cipherSuite=none protocol=http/1.1}
I/System.out: Content-Type: application/x-www-form-urlencoded
I/System.out: Content-Length: 33
I/System.out: Host: test.essaybot.com
I/System.out: Connection: Keep-Alive
I/System.out: Accept-Encoding: gzip
I/System.out: User-Agent: okhttp/3.11.0

响应:

I/System.out: INFO: Received response for http://test.essaybot.com/msg/tag_search in 62.2ms
I/System.out: Cache-Control: no-cache
I/System.out: Content-Encoding: gzip
I/System.out: Content-Length: 139
I/System.out: Content-Type: application/json
I/System.out: Set-Cookie: PHP_SESSION=0Q4rZJplDjrUNB4ZbWAG; Path=/; Max-Age=2592000
I/System.out: Set-Cookie: VISITOR_ID=65xGr53M1xM0waK8; Path=/; Max-Age=31536000
I/System.out: Date: Wed, 29 Aug 2018 20:45:06 GMT
I/System.out: INFO: Received response body bytes: 
I/System.out:  [31, -117, 8, 0, 0, 0, 0, 0, 0, -1, 44, -51, 65, 10, -62, 64, 12, 5, -48, -85, 72, -42, 93, -72, -18, -50, -91, 103, 16, -111, -23, 52, -83, 31, 66, -90, 100, 50, -94, -120, 119, -105, 116, -70, 9, 47, -16, -109, -1, 37, 54, 123, 104, -95, -15, 60, -112, 113, 109, -30, 52, -34, -24, 50, -65, 88, -67, 25, -45, 16, 70, -34, 97, 30, 115, 49, -28, 20, -128, 9, -108, 107, 80, -33, 96, -1, -12, 12, 22, 100, 36, 57, 93, -43, 89, 4, 43, 107, -65, -34, -74, 61, 58, -49, -56, -114, -94, -31, 86, -35, -110, -32, -8, 54, -23, 20, 88, -95, 107, -81, 101, 115, -44, 99, -109, 92, -98, 69, 66, 21, -119, -18, -65, 63, 0, 0, 0, -1, -1] 
I/System.out:  With length: 139

该服务器在我们的Web和iOS端均可正常运行。直到大约两个月前,它在没有网络更改的情况下突然停止工作时,在android上也可以正常工作。还有什么可能导致此错误?

--------------------------------------更新了-------- ------------------------------

enter image description here 似乎缓冲区中的数据是可读的,因为从上面的调试器中,在缓冲区变量之后标注了可读的文本([size=185 text={"err_no":0,"result":["Adventure","Advice","Art","Africa","Airli…])。另外,来自调试器的数据与记录的数据不同:

data = {byte[8192]@4418} 
 0 = 123
 1 = 34
 2 = 101
 3 = 114
 4 = 114
 5 = 95
 6 = 110
 7 = 111
 8 = 34
 9 = 58
 10 = 48
 11 = 44
 12 = 34
 13 = 114
 14 = 101
 15 = 115
 16 = 117
 17 = 108
 18 = 116
 19 = 34
 20 = 58
 21 = 91
 22 = 34
 23 = 65
 24 = 100
 25 = 118
 26 = 101
 27 = 110
 28 = 116
 29 = 117
 30 = 114
 31 = 101
 32 = 34
 33 = 44
 34 = 34
 35 = 65
 36 = 100
 37 = 118
 38 = 105
 39 = 99
 40 = 101
 41 = 34
 42 = 44
 43 = 34
 44 = 65
 45 = 114
 46 = 116
 47 = 34
 48 = 44
 49 = 34
 50 = 65
 51 = 102
 52 = 114
 53 = 105
 54 = 99
 55 = 97
 56 = 34
 57 = 44
 58 = 34
 59 = 65
 60 = 105
 61 = 114
 62 = 108
 63 = 105
 64 = 110
 65 = 101
 66 = 115
 67 = 34
 68 = 44
 69 = 34
 70 = 65
 71 = 110
 72 = 120
 73 = 105
 74 = 101
 75 = 116
 76 = 121
 77 = 34
 78 = 44
 79 = 34
 80 = 65
 81 = 114
 82 = 116
 83 = 105
 84 = 102
 85 = 105
 86 = 99
 87 = 105
 88 = 97
 89 = 108
 90 = 32
 91 = 73
 92 = 110
 93 = 116
 94 = 101
 95 = 108
 96 = 108
 97 = 105
 98 = 103
 99 = 101
 100 = 110
 101 = 99
 102 = 101
 103 = 34
 104 = 44
 105 = 34
 106 = 65
 107 = 112
 108 = 112
 109 = 115
 110 = 34
 111 = 44
 112 = 34
 113 = 65
 114 = 100
 115 = 100
 116 = 105
 117 = 99
 118 = 116
 119 = 105
 120 = 111
 121 = 110
 122 = 34
 123 = 44
 124 = 34
 125 = 65
 126 = 117
 127 = 115
 128 = 116
 129 = 114
 130 = 97
 131 = 108
 132 = 105
 133 = 97
 134 = 34
 135 = 44
 136 = 34
 137 = 65
 138 = 105
 139 = 114
 140 = 98
 141 = 110
 142 = 98
 143 = 34
 144 = 44
 145 = 34
 146 = 65
 147 = 103
 148 = 105
 149 = 110
 150 = 103
 151 = 34
 152 = 44
 153 = 34
 154 = 65
 155 = 100
 156 = 118
 157 = 101
 158 = 114
 159 = 116
 160 = 105
 161 = 115
 162 = 105
 163 = 110
 164 = 103
 165 = 34
 166 = 44
 167 = 34
 168 = 65
 169 = 108
 170 = 99
 171 = 111
 172 = 104
 173 = 111
 174 = 108
 175 = 34
 176 = 44
 177 = 34
 178 = 65
 179 = 115
 180 = 105
 181 = 97
 182 = 34
 183 = 93
 184 = 125
 185 = 0
 186 = 0
 187 = 0
 188 = 0
 189 = 0
 190 = 0
 191 = 0
 192 = 0
 193 = 0
 194 = 0
 195 = 0
 196 = 0
 197 = 0
 198 = 0
 199 = 0 

-----------------------更新----------------------- -

我使用调试器来跟踪问题,并且好像压缩后的响应被解压缩了两次。如所附图片所示,InflaterSource.java中的读取被调用两次。异常是在第二次被解压缩时抛出的。

The first time <code>read</code> is called 第一次叫read

The second time <code>read</code> is called 第二次调用read时会引发异常

3 个答案:

答案 0 :(得分:2)

服务器数据已损坏。应该包含一个gzip预告片以指示流的结尾,并且丢失了。

答案 1 :(得分:0)

您可以使用此代码获取输入流。我希望它对您有用。

private static String getResponseString(Response response) {
    try {
        InputStream inputStream;
        String contentEncodingHeader = response.header("Content-Encoding");
        if (contentEncodingHeader != null && contentEncodingHeader.equals("gzip")) {
            // Read the zipped contents.
            inputStream = new GZIPInputStream(response.body().byteStream());
        } else {
            // Read the normal contents.
            inputStream = response.body().byteStream();
        }

        // Create and return buffered reader.
        BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
        // Read stream.
        StringBuilder sb = new StringBuilder("");
        String line;
        while ((line = br.readLine()) != null) {
            sb.append(line.trim());
        }
        // Close everything.
        response.body().close();
        inputStream.close();
        br.close();
        return sb.toString();
    } catch (IOException e) {
        return "";
    }
}

答案 2 :(得分:0)

我在对随机网站的改装GET请求中遇到此错误,

 @Headers("Accept-Encoding: identity")

进行修复。

身份 指示身份功能(即无压缩或修改)。即使不存在该值,也始终被认为是可以接受的。