java.io.EOFException: неожиданный конец входного потока ZLIB, читающего сайт в кодировке gzip
У меня проблемы со сжатием некоторых сайтов. Следующий код должен работать нормально, но выдает EOFException
, Все основные браузеры могут загружать сайт, и у меня также нет проблем с использованием curl с gzip.
public static void main(String[] args) throws IOException {
URL url = new URL("http://www.ddanzi.com");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestProperty("Accept-Encoding", "gzip");
System.out.println("Encoding: " + connection.getContentEncoding());
System.out.println("Bytes: " + IOUtils.toByteArray(new GZIPInputStream(connection.getInputStream())).length);
}
Это будет вывод:
Encoding: gzip
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:117)
at java.io.FilterInputStream.read(FilterInputStream.java:107)
at org.apache.commons.io.IOUtils.copyLarge(IOUtils.java:1792)
at org.apache.commons.io.IOUtils.copyLarge(IOUtils.java:1769)
at org.apache.commons.io.IOUtils.copy(IOUtils.java:1744)
at org.apache.commons.io.IOUtils.toByteArray(IOUtils.java:462)
at Test.main(Test.java:18)
И это не единственный сайт, у меня проблемы с кодировкой gzip. У меня тоже проблемы с
- mgtv.com
- yxdown.com
- weather.com.cn
- ebrun.com
Я делаю что-то неправильно?
У меня система Win7 x64, Java 8 Update 102.
Заранее спасибо!
Изменить: я мог бы просто прочитать поток и проглотить исключение, но в момент возникновения исключения я мог потерять байты bufferSize и получить поврежденный / неполный документ. Есть ли способ обойти эту проблему (кроме как установить bufferSize в 1)?
Редактировать 2: В качестве обходного пути для получения байтов до возникновения исключения можно, например, прочитать поток следующим образом:
byte[] buffer = new byte[bufferSize];
InputStream inputStream = connection.getInputStream():
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
while(true) {
int read = inputStream.read(buffer);
if (read == -1) break;
baos.write(buffer, 0, read);
}
}catch(Exception e) {
// Just swallow or Log or something...
}
byte[] result = baos.toByteArray();
Но проблема здесь в том, как выбрать bufferSize? Когда он установлен, например, на 1000, и в какой-то момент, как при чтении последнего из 1000 байтов, возникает исключение, я потеряю все правильно прочитанные 999 байтов прямо перед этим. Идеальным значением для полноты будет 1, но это ОЧЕНЬ МЕДЛЕННО.
Итак, как получить все правильно читаемые данные без потери производительности?
2 ответа
Причина, по которой вы видите это исключение, заключается в том, что сервер отвечает неправильно. Пытаться http://www.google.com
вместо этого вы увидите, что ваш код работает (вы можете получить ответ 302, просто следуйте перенаправлению).
Что вы можете сделать, это сделать ваш код более надежным. Имейте в виду, что сервер может и будет отвечать на все. Например, вы могли попросить gzip
кодировка, но сервер может выбрать, чтобы вернуть простой текст. И код должен иметь дело с такими ситуациями.
Почему-то некоторые сайты из списка возвращают усеченные gzip
содержание. Вы можете проверить это вручную, используя curl
curl -H "Accept-Encoding: gzip" http://www.ebrun.com/ 2>/dev/null \
| zcat >/dev/null
gzip: skipping: <stdin>: corrupted -- missing trailer
Таким образом, ваш код действителен. Вы должны винить сайты.