2015-05-05 7 views
0

Я давно застрял в этой проблеме. У меня есть googled относительно этого, а также видел все ссылки, связанные с «chunked» в SO. Итак, наконец, решил опубликовать этот вопрос. Позвольте мне рассказать о проблеме. У меня есть Java-код, который читает ответ от HTTPS, используя сокет. Ответ получен правильно, и все идет хорошо, если кодирование передачи не «обрывается». Я пытаюсь прочитать chunked ответ сокета как массив байтов, и когда я преобразовываю его в строку, ответ нечитабелен. Я подозреваю, что я делаю что-то неправильно в обработке данных куска. Из-за этой проблемы я также получаю исключение «Не в формате GZip», когда я пытаюсь выполнить распаковку ответа. Код, который я использую для обработки ломти являетсяПолучение ответа на вызов HTTPS не работает

int chunkLength; 

    do { 
     String lengthLine = inStream.readLine(); 
     if (lengthLine == null) { 
      return false; 
     } 
     chunkLength = Integer.parseInt(lengthLine.trim(), 16); 
     if (chunkLength > 0) { 
      byte[] chunk = new byte[chunkLength]; 
      int bytesRead = inStream.read(chunk); 
      if (bytesRead < chunkLength) { 
       return false; 
      } 
      //Burn a CR/LF 
      inStream.readLine(); 
     }//if chunkLength 
    } while (chunkLength > 0) ; 
    return true; 

Как я новичок задавать вопрос в SO я могу отсутствовать некоторые (вероятно, много) детали, которые могут быть необходимы для вас для подачи раствора. Пожалуйста, простите меня в таком случае и сообщите мне, если вам понадобится дополнительная информация об этом. Любая помощь будет принята с благодарностью. Приветствия.

+1

Почему? Почему бы не использовать 'HttpURLConnection', который делает все это для вас? – EJP

+0

Спасибо за ваш быстрый ответ. Это ограничение в продукте, которое мы должны использовать сокеты. Фактически мы устанавливаем прокси в браузере для записи HTTP-трафика, и мы читаем записанный трафик с помощью сокета. –

+0

'HttpURLConnection' использует сокеты. Если кто-то устанавливает ограничение, определяющее, какие классы вы используете, их не должно быть. – EJP

ответ

0

Есть три проблемы, которые я вижу в этом коде:

  1. вы не принимая во внимание, что отдельные куски могут включать расширенную информацию о том, что вы не пропуская. Это не часто, но это часть спецификации, поэтому вы должны ее кодировать. В противном случае ваш вызов Integer.parseInt() не удастся, если вы когда-нибудь столкнетесь с ним.

  2. Вы не читаете все данные куска. Поскольку вы используете inStreeam.read(), у него есть возможность вернуть меньшее количество байтов, чем запрошено. Не прекращайте чтение, если это произойдет, это нормальное поведение для сокета. Вам необходимо позвонить read() в цикле до chunkLength. Количество байтов получено в полном объеме. Только прекратите чтение, если сообщается об ошибке реального.

  3. Вы не читаете конечные HTTP-заголовки, которые появляются после последнего фрагмента. Даже если заголовков нет, для завершения HTTP-ответа все еще есть терминатор CRLF.

Попробуйте что-то больше, как это:

try { 
    String line; 

    do { 
     // read the chunk header 
     line = inStream.readLine(); 
     if (line == null) { 
      return false; 
     } 
     // ignore any extensions after the chunk size 
     int idx = line.indexOf(';'); 
     if (idx != -1) { 
      line = line.substring(0, idx); 
     } 
     // parse the chunk size 
     int chunkLength = Integer.parseInt(line, 16); 
     if (chunkLength < 0) { 
      return false; 
     } 
     // has the last chunk been reached? 
     if (chunkLength == 0) { 
      break; 
     } 
     // read the chunk data 
     byte[] chunk = new byte[chunkLength]; 
     int offset = 0; 
     do { 
      int bytesRead = inStream.read(chunk, offset, chunkLength-offset); 
      if (bytesRead < 0) { 
       return false; 
      } 
      offset += bytesRead; 
     } while (offset < chunkLength); 
     // burn a CRLF at the end of the chunk 
     inStream.readLine(); 
     // now do something with the chunk... 
    } while (true); 

    // read trailing HTTP headers 
    do { 
     line = inStream.readLine(); 
     if (line == null) { 
      return false; 
     } 
     // has the last header been read? 
     if (line.isEmpty()) { 
      break; 
     } 
     // process the line as needed... 
    } while (true); 

    // all done 
    return true; 
} 
catch (Exception e) { 
    return false; 
} 

С учетом сказанного, имейте в виду, что CHUNKING не отрицает тот факт, что TCP/HTTP позволяет для потоковой передачи байтов. Каждый chunk представляет собой лишь небольшую часть больших данных. Поэтому не пытайтесь преобразовать каждого человека chunk как есть в строку или попытаться распаковать его как полный блок. Вам необходимо собрать chunk s в выбранный вами файл/контейнер, а затем обработать все собранные данные в целом после того, как вы достигнете конца ответа HTTP. Если вы не нажимаете куски в потоковый процессор, такой как декомпрессор GZip, который поддерживает потоковое потоковое вещание. И если вам нужно преобразовать собранные данные в String, убедитесь, что вы используете charset, который указан в заголовке ответа HTTP Content-Type (или соответствующий по умолчанию, если не указано charset), поэтому собранные данные декодируются на Java правильная строковая кодировка UTF-16.

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