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

Таким образом, ваш код действителен. Вы должны винить сайты.

Другие вопросы по тегам