Подтвердить что ты не робот

Чтение ответа "chunked" с помощью 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: Невозможно прочитать данные из транспортного соединения: соединение было закрыто.

Приведенный выше код работает очень хорошо, когда сервер возвращает ответ "не-chunked".

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

Любые идеи?


@Chuck

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

4b9b3361

Ответ 1

Не пробовал ли это с помощью "chunked" ответа, но что-то вроде этой работы?

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);

Ответ 2

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

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

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

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

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

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

Ответ 3

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

Ответ 4

Крейг, не увидев поток, который вы читаете, немного трудно отлаживать, но MAYBE вы можете изменить настройку переменной count на это:

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

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

Ответ 5

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

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();
}