2016-08-09 10 views
1

У меня возникли проблемы со сжатием некоторых веб-сайтов. Следующий код должен работать нормально, но выбрасывает EOFException. Все основные браузеры могут загружать сайт, и у меня также нет проблем с использованием curl с gzip.java.io.EOFException: Неожиданный конец входного потока ZLIB, считываемого 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.

Заранее спасибо!

Edit: я мог бы просто прочитать поток сам и глотать исключение, но в данный момент происходит исключение, я мог бы потерять 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, но это ОЧЕНЬ МЕДЛЕННО.

Итак, как получить все корректные считываемые данные без потери производительности?

+0

Вы, по крайней мере, можете прочитать несколько строк? Если да, значит, они не возвращают gzipped-данные, хотя я бы ожидал, что сообщение об ошибке будет «Не в формате GZIP» – Dici

+0

Если я прочитаю вручную с помощью буфера, я вижу, что он читает до конца, а затем бросает это исключение ... Я мог бы проглотить его и просто использовать байты, которые были прочитаны, но документ может быть не полным, а – Ph3n1x

+1

Кстати, имя всех этих сайтов кажется подозрительным чуваком ... – Dici

ответ

2

Причина, по которой вы видите это исключение, заключается в том, что сервер отвечает неправильно. Вместо этого попробуйте http://www.google.com, и вы увидите, что ваш код работает (вы можете получить ответ 302, просто выполните перенаправление).

Что вы можете сделать, это сделать ваш код более надежным. Имейте в виду, что сервер может и будет отвечать на все. Например, вы можете запросить кодировку gzip, но сервер может выбрать возврат обычного текста. И код должен иметь дело с такими ситуациями.

+0

Я знаю, что сервер может ответить любым способом (с кодировкой gzip или без нее). Это был просто короткий фрагмент, который я создал, чтобы показать страдания. И пока браузер может разобрать его, моя программа также должна ... – Ph3n1x

+0

Я верю, что для сломанных веб-сайтов вы должны вернуться к кодировке «identity». Вероятно, это то, что делают браузеры за сценой. –

+0

Проблема в том, что данные действительно кодируются gzip. Как вы говорите, сервер отвечает неправильно. Но тем не менее, мне нужны все байты, которые я мог бы получить. – Ph3n1x

1

По некоторым причинам некоторые сайты из списка возвращаются усеченным gzip. Вы можете проверить его вручную с помощью curl

curl -H "Accept-Encoding: gzip" http://www.ebrun.com/ 2>/dev/null \ 
    | zcat >/dev/null 
gzip: skipping: <stdin>: corrupted -- missing trailer 

Так что ваш код действителен. Вы должны обвинять веб-сайты.

+0

Неверный код. Он должен проверить возвращенное кодирование контента, прежде чем считать, что он GZipped. – EJP

+0

@ EJP хорошо ... Код, конечно, нуждается в улучшениях, но, как правило, это более или менее правильный способ чтения gzipped-данных. В случае 'http: // www.ebrun.com'' Content-Encoding' является 'gzip', но поток поврежден. – vsminkov

+0

@vsminkov: Я ожидал этого. Знаете ли вы какое-нибудь обходное решение? – Ph3n1x

 Смежные вопросы

  • Нет связанных вопросов^_^