为什么我在使用 HttpClient 时收到“响应提前结束”?

问题描述 投票:0回答:4

我在.Net Core 中的第一个 HTTP 客户端代码。 服务器也在我的电脑上运行,所以我想将其发送到本地主机。

在有人在这里推荐之后,我添加了内部异常的打印,但这对我来说还不足以理解问题。

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).Result;
            }
            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 Result;
        }
        
    }

}

我从 catch 内的循环收到的错误是:

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 命令才能建立安全连接?

编辑2: 在 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)
c# http .net-core httpclient
4个回答
18
投票

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 证书验证,如果您尝试调用没有/无效 SSL 证书的 HTTPS 端点,则会抛出异常。您可能没有在您的计算机上正确设置本地主机证书。

目前,您可以通过使用

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
投票

扩展 ID:DurableFunctionsMonitor.durablefunctionsmonitor 名称: 耐用功能监视器 ID:DurableFunctionsMonitor.durablefunctionsmonitor 描述:Azure Durable Functions 的监视/调试 UI 工具 版本:6.2.0 发行商: DurableFunctionsMonitor VS Marketplace 链接:

https://marketplace.visualstudio.com/items?itemName=DurableFunctionsMonitor.durablefunctionsmonitor

一旦安装在 LocalStorageEmulator 下,就会出现一些 TaskHub,删除所有这些 TaskHub 并重新启动 Visual Studio。这将解决您的问题。


0
投票

var handler = new WinHttpHandler(); handler.SslProtocols = System.Security.Authentication.SslProtocols.Tls12; handler.TcpKeepAliveEnabled = true; using (var hc = new HttpClient(handler)) { return wc.GetStringAsync(new Uri(apiUrl)).GetAwaiter().GetResult(); }



0
投票

var conn = new HttpClient(); conn.DefaultRequestHeaders.Accept.Clear(); conn.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); conn.DefaultRequestHeaders.UserAgent.ParseAdd("OldWhitey");

我的端点也是用 C# (ASP.NET) 编写的。以前似乎不需要了解 UserAgent,但从 2024 年 6 月开始需要它。我不知道现在还有哪些其他标题是必需的。

© www.soinside.com 2019 - 2024. All rights reserved.