Чтение "фрагментированного" ответа с помощью HttpWebResponse

У меня возникают проблемы с чтением "фрагментированного" ответа при использовании StreamReader для чтения потока, возвращаемого GetResponseStream () из HttpWebResponse:

// response is an HttpWebResponse
StreamReader reader = new StreamReader(response.GetResponseStream());
string output = reader.ReadToEnd(); // throws exception...

Когда вызывается метод reader.ReadToEnd(), я получаю следующее исключение System.IO.IOException: Невозможно прочитать данные из транспортного соединения: соединение было закрыто.

Приведенный выше код отлично работает, когда сервер возвращает «не фрагментированный» ответ.

Единственный способ заставить его работать - использовать HTTP / 1.0 для начального запроса (вместо HTTP / 1.1, используемого по умолчанию), но это похоже на неудачный обходной путь.

Есть идеи?


@Chuck

Ваше решение работает очень хорошо. Он по-прежнему вызывает то же исключение IOExeception при последнем Read (). Но после проверки содержимого StringBuilder похоже, что все данные были получены. Так что, возможно, мне просто нужно обернуть Read () в try-catch и проглотить «ошибку».

Чтобы прочитать фрагментированный ответ, вам нужно следовать en.wikipedia.org/wiki/Chunked_transfer_encoding

user1222828 21.02.2012 11:46

Я наблюдаю такое поведение при подключении .NET 4.6 к PowerDNS 3.4.5 HTTP REST API. Обходные пути не помогают. Если я проглочу исключение, я потеряю часть ответа.

Jordan Rieger 06.05.2016 02:23
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
11
2
19 813
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Ответ принят как подходящий

Не пробовали это с "фрагментированным" ответом, но сработает ли что-то подобное?

StringBuilder sb = new StringBuilder();
Byte[] buf = new byte[8192];
Stream resStream = response.GetResponseStream();
string tmpString = null;
int count = 0;
do
{
     count = resStream.Read(buf, 0, buf.Length);
     if (count != 0)
     {
          tmpString = Encoding.ASCII.GetString(buf, 0, count);
          sb.Append(tmpString);
     }
}while (count > 0);

Это опасно для многобайтовых кодировок (т.е. не ASCII), потому что нет гарантии, что чтение будет выровнено по границам символов.

spender 11.05.2011 17:02

@Chuck Вы не можете просто использовать ASCII, вам нужно выяснить, какая кодировка фактически используется, то есть с помощью Content-Type, а затем использовать это для "GetString"

Evgeniy Berezovsky 18.10.2011 09:42

У меня была такая же проблема (вот как я здесь оказался :-). В конце концов отследил это до того факта, что фрагментированный поток недействителен - окончательный фрагмент нулевой длины отсутствовал. Я придумал следующий код, который обрабатывает как действительные, так и недопустимые потоки с фрагментами.

using (StreamReader sr = new StreamReader(response.GetResponseStream(), Encoding.UTF8))
{
    StringBuilder sb = new StringBuilder();

    try
    {
        while (!sr.EndOfStream)
        {
            sb.Append((char)sr.Read());
        }
    }
    catch (System.IO.IOException)
    { }

    string content = sb.ToString();
}

Преобразование байтов в char опасно, потому что оно полностью игнорирует многобайтовые кодировки.

spender 11.05.2011 17:00

Я работаю над подобной проблемой. .Net HttpWebRequest и HttpWebRequest обрабатывают файлы cookie и перенаправляют автоматически, но не обрабатывают фрагментированное содержимое в теле ответа автоматически.

Возможно, это связано с тем, что фрагментированное содержимое может содержать больше, чем простые данные (например, имена фрагментов, завершающие заголовки).

Простое чтение потока и игнорирование исключения EOF не сработает, поскольку поток содержит больше, чем желаемое. Поток будет содержать фрагменты, и каждый фрагмент начинается с объявления своего размера. Если поток просто читается от начала до конца, окончательные данные будут содержать метаданные фрагмента (и в случае, если это gziped-контент, он не пройдет проверку CRC при распаковке).

Чтобы решить эту проблему, необходимо вручную проанализировать поток, удалив размер блока из каждого блока (а также разделители CR LF), обнаружив последний блок и сохранив только данные блока. Вероятно, где-то есть библиотека, которая делает это, я ее еще не нашел.

Полезные ресурсы:

http://en.wikipedia.org/wiki/Chunked_transfer_encodinghttp://tools.ietf.org/html/rfc2616#section-3.6.1

Попробовав множество фрагментов из StackOverflow и Google, в конечном итоге я обнаружил, что это работает лучше всего (если вы знаете данные в виде строки UTF8, в противном случае вы можете просто сохранить массив байтов и обработать соответствующим образом):

byte[] data;
var responseStream = response.GetResponseStream();
var reader = new StreamReader(responseStream, Encoding.UTF8);
data = Encoding.UTF8.GetBytes(reader.ReadToEnd());
return Encoding.Default.GetString(data.ToArray());

Я обнаружил, что большую часть времени работают другие варианты, но иногда данные усекаются. Я получил этот фрагмент из:

https://social.msdn.microsoft.com/Forums/en-US/4f28d99d-9794-434b-8b78-7f9245c099c4/problems-with-httpwebrequest-and-transferencoding-chunked?forum=ncl

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