HttpWebRequest (Основное соединение было закрыто: соединение было неожиданно закрыто).
Я разрабатываю приложение С#, которое регистрирует данные с веб-сервера. Он отправляет следующий почтовый запрос на веб-сервер и ожидает ответа.
/// <summary>
/// Function for obtaining testCgi data
/// </summary>
/// <param name="Parameters"></param>
/// <returns></returns>
private string HttpmyPost(string Parameters)
{
string str = "No response";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uriTestCGI);
request.Method = "POST";
byte[] bytes = Encoding.UTF8.GetBytes(Parameters);
request.ContentLength = bytes.Length;
Stream requestStream = request.GetRequestStream();
requestStream.Write(bytes, 0, bytes.Length);
requestStream.Close();
WebResponse response = request.GetResponse();
Stream stream = response.GetResponseStream();
StreamReader reader = new StreamReader(stream);
try
{
var result = reader.ReadToEnd();
stream.Dispose();
str = result.ToString();
reader.Dispose();
}
catch (WebException ex)
{
//System.Windows.Forms.MessageBox.Show(ex.Message);
System.Diagnostics.Trace.WriteLine(ex.Message);
}
finally
{
request.Abort();
}
return str;
}
Я получаю сообщение об ошибке
> "The underlying connection was closed: The connection was closed
> unexpectedly"
Я попытался отладить ошибку, и я использовал скрипач, чтобы проверить почтовый запрос, указанный в Firefox. К моему удивлению, когда Fiddler была моей программой, она работала отлично. Когда я закрываю скрипач, у меня такая же ошибка.
Я подозреваю, что, поскольку Fiddler действует как прокси-сервер, он может изменить некоторые настройки.
Я попытался использовать webclient, и результат был таким же.
Когда я попытался кодировать запрос в python, все работало так, как нужно, без проблем. Конечно, у меня есть возможность установить IronPython и обернуть эту конкретную функцию, однако я считаю это излишним и не хватает элегантности, поэтому я придерживаюсь более компактного подхода. Я подозреваю, что это не что иное, как настройка настройки.
Я пробовал модифицировать, и в моем случае это безразлично.
request.Accept
request.ReadWriteTimeout
request.Timeout
request.UserAgent
request.Headers
request.AutomaticDecompression
request.Referer
request.AllowAutoRedirect
//request.TransferEncoding
request.Expect
request.ServicePoint.Expect100Continue
request.PreAuthenticate
request.KeepAlive
request.ProtocolVersion
request.ContentType
С или без вышеуказанных настроек код работает, когда Fiddler захватывает данные.
Также можно отметить, что программа дает ошибку при
WebResponse response = request.GetResponse();
UPDATE:
Следуя рекомендациям @EricLaw, я заглянул в Latency.
Я нашел эту статью
HttpWebRequest замедляется при добавлении интервала
который предложил поворот алгоритма Нагле.
Теперь нет закрытых соединений, хотя в общем ответе есть небольшое отставание (когда я использую winforms, а не async).
Ответы
Ответ 1
Я немного пишу о том, как Fiddler может "магически" исправить ситуацию здесь: http://blogs.telerik.com/fiddler/posts/13-02-28/help!-running-fiddler-fixes-my-app-
Проблема, с которой вы сталкиваетесь, на самом деле является ошибкой в самой .NET Framework. Правила HTTP таковы, что сервер может закрыть соединение KeepAlive в любое время после отправки первого ответа (например, ему не нужно принимать другой запрос в соединении, даже если клиент запрашивал поведение KeepAlive).
У .NET есть ошибка, в которой он ожидает, что сервер будет включать заголовок ответа Connection: close
, если он закроет соединение после завершения ответа. Если сервер закрывает соединение без заголовка Connection: close
(полностью допустимого для RFC2616),.NET будет сталкиваться с закрытым соединением при попытке отправить следующий запрос в соединении, и он выкинет это исключение. То, что должен делать .NET, - это тихое создание нового соединения и повторная отправка запроса на это новое соединение.
Fiddler решает эту проблему, потому что все равно, закрывает ли сервер соединение, и поддерживает соединение с клиентом. Когда клиент отправляет второй запрос, Fiddler пытается повторно использовать свое соединение с сервером, замечает, что он закрыт, и тихо создает новое соединение.
Вы можете уменьшить эту проблему в своем коде с помощью:
- Отключение keepalive по запросу (это ухудшает производительность)
- Автоматическое исправление исключения и повторная попытка
- Изменение сервера для продолжительного подключения соединений
Подход №3 работает только в том случае, если вы управляете сервером, и поскольку клиент может находиться за шлюзом/прокси-сервером, который закрывает соединения после использования, вероятно, вы также должны использовать подход № 2.
Ответ 2
предложение и вопрос:
1) если вы действительно хотите посмотреть, что происходит, установите Wireshark. Он покажет вам, что именно отправляется/принимается. и это позволит сравнить с скрипачом.
Я предполагаю, что у вас отсутствует заголовок, например request.ContentType = "....", но только wirehark покажет вам, какой из них (отправляется через вашу рабочую альтернативу, а не отправляется вашим HttpWebRequest).
2) вы получаете ошибку внутри содержимого ответа HTTP, или это исключение, и если это исключение, оно попадает в ваш catch или происходит во время запроса, перед выражением try?
Ответ 3
Fiddler работает как интернет-прокси. Если ваш код работает во время работы Fiddler (и, возможно, также из браузера), у вас может возникнуть проблема с настройками прокси-сервера.