Чтение «чанкованного» ответа с помощью HttpWebResponse

У меня возникают проблемы при чтении ответа "chunked" при использовании 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 и проглотить «ошибку».

19.08.2008 21:28:53
Чтобы прочитать ответ в виде фрагментов, вам нужно следовать en.wikipedia.org/wiki/Chunked_transfer_encoding
user1222828 21.02.2012 07:46:43
Такое поведение наблюдается при подключении .NET 4.6 к API-интерфейсу HTTP REST PowerDNS 3.4.5. Обходные пути не помогают. Если я проглочу исключение, я потеряю часть ответа.
Jordan Rieger 5.05.2016 23:23:21
5 ОТВЕТОВ
РЕШЕНИЕ

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

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);
3
19.08.2008 23:54:37
Это опасно для многобайтовых кодировок (то есть не ASCII), потому что нет гарантии, что чтения будут выровнены по границам символов.
spender 11.05.2011 13:02:12
@Chuck Вы не можете просто использовать ASCII, вам нужно выяснить, какая кодировка на самом деле используется, то есть с помощью Content-Type, а затем использовать это для «GetString»
Eugene Beresovsky 18.10.2011 05:42:15

Крейг, не видя потока, который вы читаете, его немного сложно отладить, но МОЖЕТЕ изменить настройку переменной count следующим образом:

count = resStream.Read(buf, 0, buf.Length-1);

Это что-то вроде хака, но если последнее чтение убивает вас и не возвращает никаких данных, то теоретически это поможет избежать проблемы. Я до сих пор удивляюсь, почему поток делает это.

-1
20.08.2008 13:41:13

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

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();
}
-1
9.12.2008 11:26:48
Приведение байтов к символу опасно, потому что оно полностью игнорирует многобайтовые кодировки.
spender 11.05.2011 13:00:52

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

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

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

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

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

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

1
19.03.2013 10:50:16

Попробовав множество фрагментов из 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

0
22.07.2019 16:11:29