httpWebRequest (Базовое соединение было закрыто: соединение было неожиданно закрыто.)

Я занимаюсь разработкой приложения на C#, которое регистрирует данные с веб-сервера. Он отправляет следующий почтовый запрос на веб-сервер и ожидает ответа.

    /// <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"

Я попытался отладить ошибку, и я использовал fiddler, чтобы проверить почтовый запрос, полученный от Firefox. К моему удивлению, когда Fiddler был моей программой, она работала отлично. Когда я закрываю скрипач, у меня возникает та же ошибка.

Я подозреваю, что, поскольку Fiddler действует как прокси, он может изменить некоторые настройки. Я попытался с помощью веб-клиента, и результат был таким же.

Когда я пытался кодировать запрос в 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();

ОБНОВЛЕНИЕ: Следуя предложениям @EricLaw, я изучил Latency. Я обнаружил, что эта статья HttpWebRequest становится медленнее при добавлении интервала, который предлагает поворот алгоритма Nagle. Теперь нет закрытых соединений, хотя в общем отклике есть небольшая задержка (когда я использую winforms, а не async).

3 ответа

Я немного расскажу о том, как 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 пытается повторно использовать свое соединение с сервером, замечает, что оно закрыто, и молча создает новое соединение.

Вы можете решить эту проблему в своем коде:

  1. Отключение поддержки активности по запросу (это снижает производительность)
  2. Перехват исключения и повторная попытка автоматически
  3. Изменение сервера, чтобы поддерживать соединения дольше

Подход № 3 работает только в том случае, если вы контролируете сервер и поскольку клиент может находиться за шлюзом / прокси-сервером, который закрывает соединения после использования, вам, вероятно, следует также использовать подход № 2.

Предложение и вопрос: 1) если вы действительно хотите посмотреть, что происходит, установите Wireshark. Он покажет вам, что именно отправлено / получено. и это позволит сравнить с скрипачом. Я полагаю, что вам не хватает заголовка, например request.ContentType = "....", но только wireshark покажет вам, какой из них (отправляется через вашу рабочую альтернативу, но не отправляется вашим HttpWebRequest).

2) вы получаете сообщение об ошибке в содержимом ответа http, или это исключение, и если это исключение, оно попадает в ваш запрос или происходит во время запроса перед вашим оператором try?

Fiddler работает как интернет-прокси. Если ваш код работает во время работы Fiddler (и, возможно, также из браузера), то у вас могут быть проблемы с настройками прокси.

Другие вопросы по тегам