Почему я получаю «Ответ закончился преждевременно» при использовании HttpClient в C#?

#c# #http #.net-core #httpclient

Вопрос:

Мой первый код HTTP-клиента в .Net Core. Сервер также работает на моем компьютере, поэтому я хочу отправить его на локальный хост.

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

 namespace HTTPClient
{
    // The object I want to send
    public class Msg
    {
        public string ID { get; set; }
        public string Data { get; set; }
        public int RSSIR { get; set; }
        public int RSSIT { get; set; }
        public int Slot { get; set; }
    }

    class Program
    {
        static Msg msg = new Msg
        {
            ID = "00CC",
            Data = "9F4CC",
            RSSIR = 123, 
            RSSIT = 321,
            Slot = 1
        };

        static void Main(string[] args)
        {
            string url = "http://127.0.0.1:5001";
            Console.WriteLine("result = " , callURL(url)); 
            Console.ReadKey();
        }


        public static bool callURL(string url)
        {
            ServicePointManager.ServerCertificateValidationCallback  = (sender, cert, chain, sslPolicyErrors) => true;
            bool Result = false;
            HttpClient client = new HttpClient();
            client.BaseAddress = new Uri(url);
            client.DefaultRequestHeaders.Accept.Clear();
            HttpResponseMessage response = null;
            try
            {
                client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
                HttpContent content = new StringContent(JsonConvert.SerializeObject(msg), Encoding.UTF8, "application/json");
                response = client.PostAsync("", content).Resu<
            }
            catch (AggregateException err)
            {
                foreach (var errInner in err.InnerExceptions)
                {   // for printing the inner execption
                    Console.WriteLine("ERROR");
                    Console.WriteLine(errInner); 
                }
            }


            if (response.IsSuccessStatusCode)
            {
                Result = true;
            }
            else
            {
                Result = false;
            }
            return Resu<
        }
        
    }

}
 

Ошибка, которую я получил из цикла внутри ловушки, состоит в том, что:

 System.Net.Http.HttpRequestException: An error occurred while sending the request.
 ---> System.IO.IOException: The response ended prematurely.
   at System.Net.Http.HttpConnection.FillAsync()
   at System.Net.Http.HttpConnection.ReadNextResponseHeaderLineAsync(Boolean foldedHeadersAllowed)
   at System.Net.Http.HttpConnection.SendAsyncCore(HttpRequestMessage request, CancellationToken cancellationToken)
   --- End of inner exception stack trace ---
   at System.Net.Http.HttpConnection.SendAsyncCore(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.SendWithNtConnectionAuthAsync(HttpConnection connection, HttpRequestMessage request, Boolean doRequestAuth, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.SendWithRetryAsync(HttpRequestMessage request, Boolean doRequestAuth, CancellationToken cancellationToken)
   at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.HttpClient.FinishSendAsyncBuffered(Task`1 sendTask, HttpRequestMessage request, CancellationTokenSource cts, Boolean disposeCts)
 

Как я могу понять, почему я не могу отправить сообщение на сервер?
Может ли содержимое сообщения нарушить создание соединения?

Я проверил сервер у другого клиента, и он работает, поэтому проблема должна быть в моем коде.

ИЗМЕНИТЬ: Сервер использует https, поэтому я также изменил свой URL на https, и это ошибка, которую я получил:

 System.Net.Http.HttpRequestException: The SSL connection could not be established, see inner exception.
 ---> System.Security.Authentication.AuthenticationException: The remote certificate is invalid according to the validation procedure.
   at System.Net.Security.SslStream.StartSendAuthResetSignal(ProtocolToken message, AsyncProtocolRequest asyncRequest, ExceptionDispatchInfo exception)
   at System.Net.Security.SslStream.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslStream.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslStream.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslStream.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslStream.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslStream.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslStream.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslStream.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslStream.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslStream.PartialFrameCallback(AsyncProtocolRequest asyncRequest)
--- End of stack trace from previous location where exception was thrown ---
   at System.Net.Security.SslStream.ThrowIfExceptional()
   at System.Net.Security.SslStream.InternalEndProcessAuthentication(LazyAsyncResult lazyResult)
   at System.Net.Security.SslStream.EndProcessAuthentication(IAsyncResult result)
   at System.Net.Security.SslStream.EndAuthenticateAsClient(IAsyncResult asyncResult)
   at System.Net.Security.SslStream.<>c.<AuthenticateAsClientAsync>b__65_1(IAsyncResult iar)
   at System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar, Func`2 endFunction, Action`1 endAction, Task`1 promise, Boolean requiresSynchronization)
--- End of stack trace from previous location where exception was thrown ---
   at System.Net.Http.ConnectHelper.EstablishSslConnectionAsyncCore(Stream stream, SslClientAuthenticationOptions sslOptions, CancellationToken cancellationToken)
   --- End of inner exception stack trace ---
   at System.Net.Http.ConnectHelper.EstablishSslConnectionAsyncCore(Stream stream, SslClientAuthenticationOptions sslOptions, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.ConnectAsync(HttpRequestMessage request, Boolean allowHttp2, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.CreateHttp11ConnectionAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.GetHttpConnectionAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.SendWithRetryAsync(HttpRequestMessage request, Boolean doRequestAuth, CancellationToken cancellationToken)
   at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.HttpClient.FinishSendAsyncBuffered(Task`1 sendTask, HttpRequestMessage request, CancellationTokenSource cts, Boolean disposeCts)

 

Нужно ли мне добавлять некоторые команды SSL, чтобы установить безопасное соединение?

Edit2: Новая ошибка после добавления команды в callURL()

 ---> System.Security.Authentication.AuthenticationException: The remote certificate is invalid according to the validation procedure.
   at System.Net.Security.SslStream.StartSendAuthResetSignal(ProtocolToken message, AsyncProtocolRequest asyncRequest, ExceptionDispatchInfo exception)
   at System.Net.Security.SslStream.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslStream.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslStream.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslStream.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslStream.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslStream.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslStream.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslStream.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslStream.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslStream.PartialFrameCallback(AsyncProtocolRequest asyncRequest)
--- End of stack trace from previous location where exception was thrown ---
   at System.Net.Security.SslStream.ThrowIfExceptional()
   at System.Net.Security.SslStream.InternalEndProcessAuthentication(LazyAsyncResult lazyResult)
   at System.Net.Security.SslStream.EndProcessAuthentication(IAsyncResult result)
   at System.Net.Security.SslStream.EndAuthenticateAsClient(IAsyncResult asyncResult)
   at System.Net.Security.SslStream.<>c.<AuthenticateAsClientAsync>b__65_1(IAsyncResult iar)
   at System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar, Func`2 endFunction, Action`1 endAction, Task`1 promise, Boolean requiresSynchronization)
--- End of stack trace from previous location where exception was thrown ---
   at System.Net.Http.ConnectHelper.EstablishSslConnectionAsyncCore(Stream stream, SslClientAuthenticationOptions sslOptions, CancellationToken cancellationToken)
   --- End of inner exception stack trace ---
   at System.Net.Http.ConnectHelper.EstablishSslConnectionAsyncCore(Stream stream, SslClientAuthenticationOptions sslOptions, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.ConnectAsync(HttpRequestMessage request, Boolean allowHttp2, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.CreateHttp11ConnectionAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.GetHttpConnectionAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.SendWithRetryAsync(HttpRequestMessage request, Boolean doRequestAuth, CancellationToken cancellationToken)
   at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.HttpClient.FinishSendAsyncBuffered(Task`1 sendTask, HttpRequestMessage request, CancellationTokenSource cts, Boolean disposeCts)
 

Комментарии:

1. Сделайте catch (Exception err) , а затем Console.WriteLine(err.ToString()); — каковы полные сведения об исключении?

2. HttpClient использует асинхронный ввод — поэтому вы должны использовать async методы с await . Вы не должны использовать .Result , потому что это может привести к взаимоблокировкам.

3. @ErmiyaEskandary Значение ошибки: msg: Произошла одна или несколько ошибок. (При отправке запроса произошла ошибка.) источник: Система. Частное. Трассировка ядра: в системе. Нарезание резьбы. Задачи.Задачи. ThrowIfExceptional(логические исключения includeTaskCanceledExceptions) в системе. Нарезание резьбы. Задачи. Задача 1.GetResultCore(Boolean waitCompletionNotification) at System.Threading.Tasks.Task 1.get_Result() в HttpClient. Program.callURL(URL-адрес строки) в C:sourceHTTPClientHTTPClientProgram.cs:line 84

4. Правильно ли 127.0.0.1:5001 на 100%? Работает ли сервер? Ваш код работает так, что бы это ни было, это серверная сторона

5. @ErmiyaEskandary Я только что увидел, что сервер использует https, и я использовал HTTP, поэтому я изменил HTTP на https, и я получил новую ошибку (В сообщении)

Ответ №1:

System.IO.IOException: The response ended prematurely означает, что сервер, на который вы отправляете HTTP-запрос, закрыл соединение, не отправив полный ответ.

Это не имеет никакого отношения к вашему клиентскому коду, так как он правильно компилирует и отправляет контент.

Да, вы должны использовать await client.PostAsync , но это никак не связано с вашим вопросом.

Дважды проверьте, что http://127.0.0.1:5001 это на 100% правильно — возможно, это https:// или нет на порту 5001 .


Если это конечная точка, использующая HTTPS, вы можете получить System.Security.Authentication.AuthenticationException: The remote certificate is invalid according to the validation procedure. , как это выглядит, если вы вызываете локальную конечную точку.

.NET по умолчанию выполняет проверку SSL-сертификата и создаст исключение, если вы пытаетесь вызвать конечную точку HTTPS, для которой у вас нет/недействительного SSL-сертификата. Возможно, вы неправильно настроили сертификат localhost на своем компьютере.

На данный момент вы можете обойти проверку, установив параметр ServicePointManager.ServerCertificateValidationCallback всегда возвращаться true с помощью HttpClientHandler.DangerousAcceptAnyServerCertificateValidator

Инициализируйте ваше HttpClient подобное ниже:

 public static bool callURL(string url)
{
  bool Result = false;

  var httpClientHandler = new HttpClientHandler();
  
  #if DEBUG
  httpClientHandler.ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;
  #endif

  HttpClient client = new HttpClient(httpClientHandler);
  ...
}
 

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

Читайте: Самый опасный код в мире: проверка SSL-сертификатов в не-браузерном программном обеспечении Стэнфордского университета

Комментарии:

1. Теперь это работает. Очень странно.. Большое спасибо!

2. @RoyAncri Не пропускайте проверку сертификации в производстве, однако для разработки это будет нормально. Установка правильного SSL — сертификата на производственном сервере позволит вам удалить приведенный выше код, который представляет угрозу безопасности, если оставить его в таком виде на чем-либо, кроме сборок разработчиков-надеюсь, это поможет!

3. @ErmiyaEskandary Да, я прочитаю, как это сделать для производственного проекта. Еще раз спасибо