Сравнение HttpWebRequest и HttpClient: Обработка HTTP 100: Продолжение вызывает исключение в HttpClient, но не в HttpWebRequest - PullRequest
0 голосов
/ 27 октября 2019

Я работаю над очисткой и обновлением некоторого устаревшего кода, который каждую минуту отправляет около 1 КБ данных на сервер. Сервер находится вне моего контроля, но всегда отвечает с HTTP 100 продолжить перед отправкой HTTP 200 OK.

Старый код (см. Ниже) работает, но использует HttpWebRequest который не рекомендуется для новых разработок, поэтому я хотел бы обновить код, если это возможно. Код выполняется в фоновом режиме, поэтому нет необходимости в асинхронных вызовах.

Я написал новую реализацию устаревшего кода с помощью HttpClient, но он генерирует исключения. Я предполагаю, что исключение вызвано ответом HTTP 100 continue сервера, поскольку отправка данных на другой тестовый сервер, который не использует этот ответ, работает нормально.

Устаревший код:

    private void Legacy()
        {
            string s = "POSTDATA";
            string output = "";
            try
            {
                Encoding encoding1 = (Encoding)new ASCIIEncoding();
                HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create("http://myurl.com");
                httpWebRequest.Method = "POST";
                httpWebRequest.Timeout = 10000;
                httpWebRequest.Credentials = CredentialCache.DefaultCredentials;
                byte[] bytes = encoding1.GetBytes(s);
                httpWebRequest.Headers.Clear();
                httpWebRequest.ContentType = "application/x-www-form-urlencoded";
                httpWebRequest.Method = "POST";
                httpWebRequest.KeepAlive = true;
                httpWebRequest.Headers.Add("Accept-Language", "it");
                httpWebRequest.Headers.Add("Cache-Control", "no-cache");
                httpWebRequest.ContentLength = (long)s.Length;
                Stream requestStream = httpWebRequest.GetRequestStream();
                requestStream.Write(bytes, 0, bytes.Length);
                Stream responseStream = httpWebRequest.GetResponse().GetResponseStream();
                Encoding encoding2 = Encoding.GetEncoding("utf-8");
                StreamReader streamReader = new StreamReader(responseStream, encoding2);
                char[] buffer = new char[512];
                streamReader.Read(buffer, 0, 512);
                requestStream.Close();
                requestStream.Dispose();
                streamReader.Close();
                streamReader.Dispose();
                responseStream.Close();
                responseStream.Dispose();
                for (int index2 = 0; index2 < buffer.Length; ++index2)
                    output += buffer[index2].ToString();
                MessageBox.Show(output);
            }
            catch (Exception Ex)
            {
                MessageBox.Show(Ex.Message);
            }
        }

Новый код:

    private static readonly HttpClient _httpclient = new HttpClient();
        private void NewCode()
        {
            _httpclient.Timeout = new TimeSpan(0, 0, 5);
            _httpclient.DefaultRequestHeaders.Add("Cache-Control", "no-cache");
            _httpclient.DefaultRequestHeaders.Add("Connection", "keep-alive");
            _httpclient.DefaultRequestHeaders.Add("Accept-Language", "it");

            var t = Task.Run(TEST);
            t.Wait();
            string tmp = t.Result;
            MessageBox.Show(tmp);
        }

        private static async Task<String> TEST()
        {
            try
            {
                string s = "POSTDATA";
                StringContent cont = new StringContent(s, Encoding.ASCII, "application/x-www-form-urlencoded");
                HttpResponseMessage Req = await _httpclient.PostAsync("http://myurl.com", cont);
                Req.EnsureSuccessStatusCode();
                string Response = await Req.Content.ReadAsStringAsync();
                return Response;
            }
            catch (Exception Ex)
            {
                MessageBox.Show(Ex.Message);
                return "";
            }
        }

Исключение: Error while copying content to a stream.
Не исключение: Unable to read data from the transport connection: The connection was closed.
Отслеживание стека:

at System.Net.ConnectStream.EndRead(IAsyncResult asyncResult)
at System.Net.Http.HttpClientHandler.WebExceptionWrapperStream.EndRead(IAsyncResult
asyncResult) 
at
System.Net.Http.StreamToStreamCopy.BufferReadCallback(IAsyncResult ar)

Я проверил запросы и ответы обеих реализаций с Wireshark, и они абсолютно одинаковы, поэтому я предполагаю, что реализация с HttpClient где-то не так. Итак, мои вопросы:

  • Есть ли проблема в моей реализации с HttpClient, или это фундаментальная проблема?
  • Есть ли другой способ сделать это без использования устаревших вещей?
  • Стоит ли вообще обновлять устаревший код?

Мне бы очень хотелось услышать ваши мысли по этому поводу.

1 Ответ

0 голосов
/ 31 октября 2019

Обходной путь:

Мне показалось, что внутри фреймворка что-то идет не так или что-то неправильно настроено. Итак, я попробовал несколько разных способов сделать один и тот же запрос HTTP POST, который я также проверил снова с помощью Wireshark.

Ниже приведен новый код, не показывающий никаких исключений, но, тем не менее, использующий HttpClient вместо HttpWebRequest.

Похоже, что я получаю то же исключение, что и раньше, если я использую ReadAsStringAsync() вместо Req.Content.ReadAsStreamAsync();. Также кажется, что имеет значение, какое значение я использую для HttpCompletionOption , потому что, если я изменю его с ResponseHeadersRead на ResponseContentRead, я также получу то же исключение снова.

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

    private static readonly HttpClient _httpclient = new HttpClient();
        private void NewCode()
        {
            _httpclient.Timeout = new TimeSpan(0, 0, 5);
            _httpclient.DefaultRequestHeaders.Add("Cache-Control", "no-cache");
            _httpclient.DefaultRequestHeaders.Add("Connection", "keep-alive");
            _httpclient.DefaultRequestHeaders.Add("Accept-Language", "it");

            var t = Task.Run(TEST3);
            t.Wait();
            string tmp = t.Result;
            MessageBox.Show(tmp);
        }

        private static async Task<String> TEST3()
        {
            try
            {
                HttpRequestMessage x = new HttpRequestMessage(HttpMethod.Post, "http://myurl.com");
                Dictionary<string, string> postParams = new Dictionary<string, string>();
                postParams.Add("Param", "Value");
                x.Content = new FormUrlEncodedContent(postParams);
                HttpResponseMessage Req = await _httpclient.SendAsync(x, HttpCompletionOption.ResponseHeadersRead);
                Req.EnsureSuccessStatusCode();

                Stream str = await Req.Content.ReadAsStreamAsync();
                Encoding encoding2 = Encoding.GetEncoding("utf-8");
                StreamReader streamReader = new StreamReader(str, encoding2);
                return streamReader.ReadToEnd();
            }
            catch (Exception Ex)
            {
                return Ex.Message;
            }
        }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...