Получение "источника исчерпан преждевременно" при раздутии gzip тела ответа HTTP
Я получаю следующую ошибку при попытке сделать HTTP-вызов с помощью okhttp:
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
правильная длина тела ответа. Вот мой логированный запрос и ответ охтпп:
Запрос:
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
Сервер отлично работает с нашим вебом и iOS заканчивается. Он также работал нормально с Android до примерно двух месяцев назад, когда он вдруг перестал работать без изменений в сети. Что еще может вызвать эту ошибку?
-------------------------------------- обновлено ----------- ---------------------------
Кажется, что данные в буфере читабельны, так как из отладчика выше читаемый текст ([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
----------------------- Обновить ------------------------
Я использовал отладчик, чтобы отследить проблему, и похоже, что gzipped ответ был распакован дважды. Как показано на рисунках, read в InflaterSource.java вызывается дважды. Исключение выдается во второй раз, когда он распаковывается.
2 ответа
У меня была эта ошибка при запросе модификации GET на случайном сайте, я добавил
@Headers("Accept-Encoding: identity")
починить это.
identity Указывает функцию идентичности (т. е. отсутствие сжатия или модификации). Это значение всегда считается приемлемым, даже если оно отсутствует.
Данные сервера повреждены. Он должен содержать трейлер GZIP, чтобы указать конец потока, и это отсутствует.
Вы можете использовать этот код для получения входного потока. Я надеюсь, что это сработает для вас.
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 "";
}
}