System.Net.Http.HttpRequestException将内容复制到流时出错

jon*_*nho 16 .net c# asp.net asp.net-web-api

我在.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偏移量,Int32大小,AsyncCallback回调,对象状态)强制关闭现有连接---内部异常堆栈跟踪的结束---在System.Net.FixedSizeReader.StartReading()的System.Net.Sockets.NetworkStream.BeginRead(Byte []缓冲区,Int32偏移量,Int32大小,AsyncCallback回调,对象状态)在System.Net.Security._SslStream.StartFrameHeader(字节[]缓冲液,的Int32偏移的Int32计数,AsyncProtocolRequest asyncRequest)在System.Net.Security._SslStream.StartReading(字节[]缓冲液,的Int32偏移的Int32计数,

随后的相同请求成功.这不是我们可以重新设置的请求,因为已经放置了业务.所以它让我们处于一种尴尬的境地.

这是我的代码:

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              
}
Run Code Online (Sandbox Code Playgroud)

第三方服务成功地将记录保存到他们的数据库中,并且在他们的结尾没有看到任何明显的例外.他们确实注意到,写入数据库的失败请求通常需要比成功请求更长的时间(大约18-30秒).

谢谢您的帮助

jon*_*nho 20

我们用2个代码更改解决了这个问题:

  1. 处理httpResponseMessage并使用简单的DTO

     using (var httpResponseMessage = await httpClient.SendAsync(httpRequestMessage))
        {
            return await CreateDto(httpResponseMessage);
        }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 将HTTP版本降级到v1.0

    var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, new Uri(url))
    {
        Version = HttpVersion.Version10,
        Content = httpContent
    };
    
    await client.SendAsync(httpRequestMessage);
    
    Run Code Online (Sandbox Code Playgroud)

具有添加此Http标头的效果

    Connection: close 
Run Code Online (Sandbox Code Playgroud)

而不是这个

    Connection: keep-alive
Run Code Online (Sandbox Code Playgroud)

  • var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, new Uri(url)) { Version = HttpVersion.Version10, Content = httpContent }; 等待 client.SendAsync(httpRequestMessage); 应该做 (2认同)

Ste*_*sky 5

我在使用共享 HttpClient 连接到服务器进行 REST 调用时遇到了类似的问题。问题最终是客户端和服务器上的 KeepAlive 超时不匹配。客户端超时由ServicePointManager 上的MaxServicePointIdleTime设置设置,默认为 100 秒。在我们的服务器中,服务器端空闲超时设置为较短的值。

与客户端相比,服务器上的超时较短会导致服务器在客户端尝试连接时偶尔关闭连接。这导致了报告的异常。

请注意,我最终发现了问题,因为我在相同条件下也收到了此异常:

System.Net.WebException: The underlying connection was closed: A connection that was expected to be kept alive was closed by the server.
Run Code Online (Sandbox Code Playgroud)