HttpClient 抛出“发送请求时发生错误。”
Posted
技术标签:
【中文标题】HttpClient 抛出“发送请求时发生错误。”【英文标题】:HttpClient throwing "An error occurred while sending the request." 【发布时间】:2020-08-22 23:30:57 【问题描述】:我有三层应用架构。
我的客户 --> 我的服务 A(REST 托管在 IIS 中)--> 其他团队的服务 X (REST)。
服务 A 是 ASP.Net 4.6.1 框架,而不是 ASP.Net Core。
Client 正在使用 HttpClient 与 A 通信,A 正在使用 HttpClient 与 X 通信。
客户端向我的服务发起了近 2500 次调用 A 和 X。
在 2500 次调用中,服务 A 随机(可能是 10 次调用)失败,但出现以下异常。它不可重现。
System.Net.Http.HttpRequestException: An error occurred while sending the request. --->
System.Net.WebException: The underlying connection was closed: An unexpected error occurred on a
receive. ---> System.IO.IOException: Unable to read data from the transport connection: An
established connection was aborted by the software in your host machine. --->
System.Net.Sockets.SocketException: An established connection was aborted by the software in your
host machine
at System.Net.Sockets.Socket.BeginReceive(Byte[] buffer, Int32 offset, Int32 size, SocketFlags
socketFlags, AsyncCallback callback, Object state)
at System.Net.Sockets.NetworkStream.BeginRead(Byte[] buffer, Int32 offset, Int32 size, AsyncCallback
callback, Object state)
--- End of inner exception stack trace ---
at System.Net.Security._SslStream.EndRead(IAsyncResult asyncResult)
at System.Net.TlsStream.EndRead(IAsyncResult asyncResult)
at System.Net.Connection.ReadCallback(IAsyncResult asyncResult)
--- End of inner exception stack trace ---
at System.Net.HttpWebRequest.EndGetResponse(IAsyncResult asyncResult)
at System.Net.Http.HttpClientHandler.GetResponseCallback(IAsyncResult ar)
--- End of inner exception stack trace --
这是我的服务 A 调用。 IIS 中的 A 调用下面的代码块并由每个请求调用。 X 正在获取用户凭据并根据用户返回数据,因此我们不会在调用之间共享 HttpClient。
var user = (System.Security.Principal.WindowsIdentity)HttpContext.Current.User.Identity;
System.Security.Principal.WindowsIdentity.RunImpersonated(user.AccessToken, () =>
static HttpClient Client = new HttpClient();
static string CallX(string[] args)
HttpClientHandler handler = new HttpClientHandler
UseDefaultCredentials = true
;
Client = new HttpClient(handler)
BaseAddress = new Uri("http://XserviceUrl/api/")
;
Client.Timeout = TimeSpan.FromSeconds(600);
var result = Client.PostAsync("Fake X controller"
, new StringContent(JsonConvert.SerializeObject(args)
, Encoding.UTF8, "application/json")).Result;
result.EnsureSuccessStatusCode();
var json = result.Content.ReadAsStringAsync().Result;
return DosomethingWithResult(json);
);
我尝试过的事情:
建议的一些 SO 帖子可能是超时问题。所以我在客户端和服务 A 中添加了 600 秒。我还将 IIS 请求超时从默认的 2 分钟更改为 10(600 秒)。
【问题讨论】:
这种类型的错误几乎总是套接字状态错误。如果您运行 Wireshark 跟踪,您将看到对方先发送 fin 或 rst。这可能是由于流量过多、路由错误,甚至是服务器端问题。为了确保它是另一方,请确保您所有的出站都正确完成,您没有淹没服务器,并且对于任何挥之不去的会话,它们都已关闭。 Netstat 可以帮助您查看落后者。然而,最可能的原因是网络状况不佳。最好的查看位置是在服务器端,并找出为什么会话会立即开始 对方“Team's service X”呢,他们没看到什么错误吗? X 服务没有发现任何错误。这就是让复制或调查变得更加困难的原因。 您是否尝试过使其完全异步而不是阻塞异步代码?它可能导致死锁。超时是怎么回事,你检查失败请求的时间戳了吗?他们是否遇到了超时? 不要在每次调用时创建新的 HttpClient,这很可能是导致此问题的原因。 HttpClient 应该被创建一次并在您的应用程序的生命周期中重复使用。最多只创建其中的几个。 aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong 【参考方案1】:经过一番挖掘,我解决了这个问题。 当 A 向 X 发送请求时,A 正在设置 Connection: keep-alive 并且 X 正在响应标头中的 Connection: Close 属性。
所以在一些调用之后,A 被打开的 tcp 连接耗尽并且随机抛出错误。
(Fiddler 帮我解决了这个问题)
所以我要做的就是设置 HttpClient 的 ConnectionClose 属性
_client.DefaultRequestHeaders.ConnectionClose = true;
【讨论】:
这对我有用,我收到了这个代码var httpMessage = await client.PostAsync(filenameURL, formContent);
的错误【参考方案2】:
我在生产环境中遇到了完全相同的问题。类似的设置和大约 30k 从客户端发送的 http 调用。错误很少发生,而且很难重现。
阅读大量帖子后,我认为这是 Microsoft 在 HttpClient 中进行连接池时的错误(在我的解决方案中,我使用 httpClientFactory)。你可以看看https://github.com/dotnet/runtime/issues/26629
在 Microsoft 解决此问题之前,为解决此问题而采取的方法:
重试策略。 Polly 已被使用,当发生此异常时,将在几秒钟后重试调用。
将请求超时时间增加到 3 分钟。
目前看来工作正常,但正如我之前提到的,很难以可控的方式重现错误。
【讨论】:
我的服务是 ASP.Net Framework,所以我不确定如何使用 httpClientFactory 没关系。我想您使用的是静态 HttpClient。如果您将超时设置为 3 分钟并使用 Polly github.com/App-vNext/Polly/wiki/Retry 该解决方案已经过测试并且对我来说效果很好 @user781700 您是否尝试了重试策略并增加了超时?我实际上刚刚完成了一些负载测试,它在相当高的压力下工作得很好。如果您还有其他问题,请告诉我 我不认为增加超时是这里的问题。所有请求在不到 1 秒的时间内完成。在我介绍新的 API (Polly) 之前,我想知道为什么会这样。 @user781700 我们增加超时的原因是连接池中的错误将有足够的时间弹出。增加超时时间后,您将看到大约 2 分钟后您将进行重试。如果您尝试捕获错误,您将看到这是 TaskCanceledException(超时)。这与 httpclient 中的错误有关。以上是关于HttpClient 抛出“发送请求时发生错误。”的主要内容,如果未能解决你的问题,请参考以下文章
C# HttpClient.SendAsync 在测试某些 URL 时抛出“发送请求时发生错误”异常
发生一个或多个错误。(发送请求时发生错误)Mailchimp 列表集成