Не удается получить ResponseStream из WebException
У меня есть настольный клиент, который общается с сервером через Http. Когда у сервера возникают проблемы с обработкой данных, он возвращает описание ошибки в JSON в теле ответа Http с правильным Http-кодом (в основном это HTTP-400).
Когда я читаю ответ HTTP-200, все хорошо, и этот код работает:
using (var response = await httpRequest.GetResponseAsync(token))
{
using (var reader = new StreamReader(response.GetResponseStream(), Encoding.GetEncoding("utf-8")))
{
return await reader.ReadToEndAsync();
}
}
Но когда происходит ошибка, и WebException генерируется и перехватывается, появляется следующий код:
catch (WebException ex)
{
if (ex.Status == WebExceptionStatus.ProtocolError)
{
using (var response = (HttpWebResponse) ex.Response)
{
using (var stream = response.GetResponseStream())
{
using (var reader = new StreamReader(stream, Encoding.GetEncoding("utf-8")))
{
var json = reader.ReadToEnd();
}
}
}
}
}
Я уже сделал что-то с этим, чтобы, возможно, заставить его работать, но происходит следующее:response.ContentLength
действителен (184), но stream.Length
0 и после этого я не могу читать JSON (это ""
) Я даже не знаю, где искать, потому что все выглядит так, как будто оно должно работать.
В чем может быть проблема?
2 ответа
После месяца почти каждодневных размышлений я нашел обходной путь.
Дело в том, что WebException.Response.GetResponseStream()
возвращает не совсем тот же поток, который был получен во время запроса (сейчас мы не можем найти ссылку на msdn), и к тому времени, когда мы получим перехватить исключение и прочитать этот поток, реальный поток ответа теряется (или что-то в этом роде, я действительно знал и не смог найти какую-либо информацию в сети, кроме как заглянуть в CLRCore, который сейчас является открытым.
Сохранить фактический ответ до отлова WebException
вы должны установить KeepAlive
Недвижимость на вашем HttpRequest
и вуаля, вы получите свой ответ, ловя исключение. Итак, рабочий код выглядит так:
try
{
var httpRequest = WebRequest.CreateHttp(Protocol + ServerUrl + ":" + ServerPort + ServerAppName + url);
if (HttpWebRequest.DefaultMaximumErrorResponseLength < int.MaxValue)
HttpWebRequest.DefaultMaximumErrorResponseLength = int.MaxValue;
httpRequest.ContentType = "application/json";
httpRequest.Method = method;
var encoding = Encoding.GetEncoding("utf-8");
if (httpRequest.ServicePoint != null)
{
httpRequest.ServicePoint.ConnectionLeaseTimeout = 5000;
httpRequest.ServicePoint.MaxIdleTime = 5000;
}
//----HERE--
httpRequest.KeepAlive = true;
//----------
using (var response = await httpRequest.GetResponseAsync(token))
{
using (var reader = new StreamReader(response.GetResponseStream(), encoding))
{
return await reader.ReadToEndAsync();
}
}
}
catch (WebException ex)
{
if (ex.Status == WebExceptionStatus.ProtocolError)
{
using (var response = (HttpWebResponse)ex.Response)
{
using (var stream = response.GetResponseStream())
{
using (var reader = new StreamReader(stream, Encoding.GetEncoding("utf-8")))
{
return reader.ReadToEnd();
//or handle it like you want
}
}
}
}
}
Я не знаю, хорошо ли поддерживать такое соединение, но так как это помогло мне прочитать реальные ответы с сервера, я думаю, что это может помочь кому-то, кто столкнулся с той же проблемой.
РЕДАКТИРОВАТЬ: Также важно не связываться с HttpWebRequest.DefaultMaximumErrorResponseLength
,
Я помню, как сталкивался с подобной проблемой раньше, и было нечто, связанное с настройкой позиции потока. Вот одно из моих решений для чтения webResponse, которое работало для меня ранее. Пожалуйста, попробуйте, если подобный подход работает для вас:-
private ResourceResponse readWebResponse(HttpWebRequest webreq)
{
HttpWebRequest.DefaultMaximumErrorResponseLength = 1048576;
HttpWebResponse webresp = null;// = webreq.GetResponse() as HttpWebResponse;
var memStream = new MemoryStream();
Stream webStream;
try
{
webresp = (HttpWebResponse)webreq.GetResponse();
webStream = webresp.GetResponseStream();
byte[] readBuffer = new byte[4096];
int bytesRead;
while ((bytesRead = webStream.Read(readBuffer, 0, readBuffer.Length)) > 0)
memStream.Write(readBuffer, 0, bytesRead);
}
catch (WebException e)
{
var r = e.Response as HttpWebResponse;
webStream = r.GetResponseStream();
memStream = Read(webStream);
var wrongLength = memStream.Length;
}
memStream.Position = 0;
StreamReader sr = new StreamReader(memStream);
string webStreamContent = sr.ReadToEnd();
byte[] responseBuffer = Encoding.UTF8.GetBytes(webStreamContent);
//......
//.......
Надеюсь это поможет!