我在.Net 4.5.2框架中使用 HttpClient 类。 我正在对第三方Web服务进行PostAsync。这篇文章80%的时间都在工作,20%的时间我们的回复被缩短了。在这种情况下,我们得到以下异常:
System.Net.Http.HttpRequestException:将内容复制到时出错 流。 ---> System.IO.IOException:无法从中读取数据 传输连接:强制关闭现有连接 远程主机。 ---> System.Net.Sockets.SocketException:现有的 连接被远程主机强行关闭 System.Net.Sockets.NetworkStream.BeginRead(Byte []缓冲区,Int32 offset,Int32 size,AsyncCallback callback,Object state)---结束 内部异常堆栈跟踪--- at System.Net.Sockets.NetworkStream.BeginRead(Byte []缓冲区,Int32 offset,Int32 size,AsyncCallback callback,Object state)at System.Net.FixedSizeReader.StartReading()at System.Net.Security._SslStream.StartFrameHeader(Byte []缓冲区,Int32 offset,Int32 count,AsyncProtocolRequest asyncRequest)at System.Net.Security._SslStream.StartReading(Byte []缓冲区,Int32 offset,Int32 count,AsyncProtocolRequest asyncRequest)at System.Net.Security._SslStream.ProcessRead(Byte []缓冲区,Int32 offset,Int32 count,AsyncProtocolRequest asyncRequest)at System.Net.TlsStream.BeginRead(Byte []缓冲区,Int32偏移量,Int32 size,AsyncCallback asyncCallback,Object asyncState)at System.Net.ConnectStream.BeginReadWithoutValidation(Byte []缓冲区, Int32偏移量,Int32大小,AsyncCallback回调,对象状态)at System.Net.ConnectStream.BeginRead(Byte []缓冲区,Int32偏移量,Int32 size,AsyncCallback回调,对象状态)at System.Net.Http.HttpClientHandler.WebExceptionWrapperStream.BeginRead(字节[] 缓冲区,Int32偏移量,Int32计数,AsyncCallback回调,对象 System)Net.Net.Http.StreamToStreamCopy.StartRead()
后续相同的请求成功。 这不是我们可以重新设置的请求,因为已经放置了业务。所以它让我们处于一种尴尬的境地。
这是我的代码:
using (var httpClient = new HttpClient())
{
httpClient.DefaultRequestHeaders.Authorization = authorizationHeader;
HttpContent httpContent = new StringContent(someXml);
//Exception occurs on next line...
var response = await httpClient.PostAsync("https://thirdpartyendpoint", httpContent);
var responseXml = await response.Content.ReadAsStringAsync();
//convert to Dto
}
第三方服务成功将记录保存到他们的数据库中,并且在他们的结尾没有看到任何明显的例外。他们确实注意到,写入数据库的失败请求通常需要比成功请求更长的时间(大约18-30秒)。
谢谢你的帮助
答案 0 :(得分:17)
我们通过2次代码更改解决了这个问题:
处理httpResponseMessage并使用简单的DTO
using (var httpResponseMessage = await httpClient.SendAsync(httpRequestMessage))
{
return await CreateDto(httpResponseMessage);
}
将HTTP版本降级为v1.0
var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, new Uri(url))
{
Version = HttpVersion.Version10,
Content = httpContent
};
await client.SendAsync(httpRequestMessage);
具有添加此Http头的效果
Connection: close
而不是这个
Connection: keep-alive
答案 1 :(得分:1)
使用共享的HttpClient连接到服务器以进行REST调用时,我遇到了类似的问题。问题最终导致客户端和服务器上的KeepAlive超时不匹配。客户端超时由ServicePointManager上的MaxServicePointIdleTime设置来设置,默认为100s。在我们的服务器中,服务器端空闲超时设置为较短的值。
与客户端相比,服务器上的超时时间较短,导致服务器仅在客户端尝试连接时偶尔关闭连接。这导致了报告的异常。
请注意,我最终找到了问题,因为在相同条件下我也收到了此异常:
System.Net.WebException: The underlying connection was closed: A connection that was expected to be kept alive was closed by the server.
答案 2 :(得分:0)
我使用HTTPClient PutAsync()方法遇到相同的错误(将内容复制到流中时出错):
file3.js
您需要指定 HttpCompletionOption.ResponseHeadersRead 标志,该标志在PutAsync中不可用,因此我切换到SendAsync:
using (StreamContent content = new StreamContent(stream))
{
HttpResponseMessage response = await client.PutAsync(url, content))
}