TL; версия DR
Когда при записи в поток запроса возникает ошибка передачи, я не могу получить доступ к ответу, даже если сервер отправляет его.
Полная версия
У меня есть приложение .NET, которое загружает файлы на сервер Tomcat, используя HttpWebRequest
. В некоторых случаях сервер закрывает поток запросов досрочно (поскольку он отказывается от файла по той или иной причине, например, недопустимое имя файла) и отправляет ответ 400 с настраиваемым заголовком, чтобы указать причину ошибки.
Проблема заключается в том, что если загруженный файл большой, поток запросов закрывается, прежде чем закончить запись тела запроса, и я получаю IOException
:
Сообщение: невозможно записать данные в транспортное соединение: существующее соединение было принудительно закрыто удаленным хостом.
InnerException:SocketException
: существующее соединение было принудительно закрыто удаленным хостом
Я могу поймать это исключение, но затем, когда я вызываю GetResponse
, я получаю WebException
с предыдущим IOException
как его внутреннее исключение и свойство null Response
. Поэтому я не могу получить ответ, даже если сервер отправляет его (отмечен с помощью WireShark).
Поскольку я не могу получить ответ, я не знаю, какова фактическая проблема. С точки зрения моего приложения, похоже, что соединение было прервано, поэтому я рассматриваю его как ошибку, связанную с сетью, и повторю загрузку... что, конечно же, снова не работает.
Как я могу обойти эту проблему и получить реальный ответ от сервера? Возможно ли это? Для меня текущее поведение выглядит как ошибка в HttpWebRequest
, или, по крайней мере, серьезная проблема с дизайном...
Вот код, который я использовал для воспроизведения проблемы:
var request = HttpWebRequest.CreateHttp(uri);
request.Method = "POST";
string filename = "foo\u00A0bar.dat"; // Invalid characters in filename, the server will refuse it
request.Headers["Content-Disposition"] = string.Format("attachment; filename*=utf-8''{0}", Uri.EscapeDataString(filename));
request.AllowWriteStreamBuffering = false;
request.ContentType = "application/octet-stream";
request.ContentLength = 100 * 1024 * 1024;
// Upload the "file" (just random data in this case)
try
{
using (var stream = request.GetRequestStream())
{
byte[] buffer = new byte[1024 * 1024];
new Random().NextBytes(buffer);
for (int i = 0; i < 100; i++)
{
stream.Write(buffer, 0, buffer.Length);
}
}
}
catch(Exception ex)
{
// here I get an IOException; InnerException is a SocketException
Console.WriteLine("Error writing to stream: {0}", ex);
}
// Now try to read the response
try
{
using (var response = (HttpWebResponse)request.GetResponse())
{
Console.WriteLine("{0} - {1}", (int)response.StatusCode, response.StatusDescription);
}
}
catch(Exception ex)
{
// here I get a WebException; InnerException is the IOException from the previous catch
Console.WriteLine("Error getting the response: {0}", ex);
var webEx = ex as WebException;
if (webEx != null)
{
Console.WriteLine(webEx.Status); // SendFailure
var response = (HttpWebResponse)webEx.Response;
if (response != null)
{
Console.WriteLine("{0} - {1}", (int)response.StatusCode, response.StatusDescription);
}
else
{
Console.WriteLine("No response");
}
}
}
Дополнительные примечания:
Если я правильно понимаю роль статуса 100 Continue
, сервер не должен отправлять его мне, если он откажется от файла. Однако, похоже, что этот статус контролируется непосредственно Tomcat и не может контролироваться приложением. В идеале, я бы хотел, чтобы сервер не отправил мне 100 Continue
в этом случае, но, по словам моих коллег, отвечающих за поддержку, нет простого способа сделать это. Поэтому я ищу решение для клиентской стороны; но если вы знаете, как решить проблему на стороне сервера, это также будет оценено.
Приложение, в котором я столкнулся с проблемой, относится к .NET 4.0, но я также воспроизвел его с 4.5.
Я не убираю время. Исключение составляет задолго до таймаута.
Я попробовал асинхронный запрос. Это ничего не меняет.
Я попытался установить версию протокола запроса на HTTP 1.0 с таким же результатом.
Кто-то еще уже зарегистрировал ошибку в Connect для этой проблемы: https://connect.microsoft.com/VisualStudio/feedback/details/779622/unable-to-get-servers-error-response-when-uploading-file-with-httpwebrequest