У меня возникают проблемы с чтением "фрагментированного" ответа при использовании 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 и проглотить «ошибку».
Я наблюдаю такое поведение при подключении .NET 4.6 к PowerDNS 3.4.5 HTTP REST API. Обходные пути не помогают. Если я проглочу исключение, я потеряю часть ответа.





Не пробовали это с "фрагментированным" ответом, но сработает ли что-то подобное?
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), потому что нет гарантии, что чтение будет выровнено по границам символов.
@Chuck Вы не можете просто использовать ASCII, вам нужно выяснить, какая кодировка фактически используется, то есть с помощью Content-Type, а затем использовать это для "GetString"
У меня была такая же проблема (вот как я здесь оказался :-). В конце концов отследил это до того факта, что фрагментированный поток недействителен - окончательный фрагмент нулевой длины отсутствовал. Я придумал следующий код, который обрабатывает как действительные, так и недопустимые потоки с фрагментами.
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 опасно, потому что оно полностью игнорирует многобайтовые кодировки.
Я работаю над подобной проблемой. .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());
Я обнаружил, что большую часть времени работают другие варианты, но иногда данные усекаются. Я получил этот фрагмент из:
Чтобы прочитать фрагментированный ответ, вам нужно следовать en.wikipedia.org/wiki/Chunked_transfer_encoding