【问题标题】:HTTPClient.PostAsync throws exception only when posting larger fileHTTPClient.PostAsync 仅在发布较大文件时引发异常
【发布时间】:2020-09-24 04:07:50
【问题描述】:

我有以下代码,用于使用 POST 将文件上传到 REST 服务。

它适用于较小的文件,但它会为较大的文件抛出异常,我的意思是大约 800 KB。

public async Task<bool> UploadInputFileAsync(FileDTO file)
{
    using (HttpClientHandler httpClientHandler = new HttpClientHandler())
    {
        httpClientHandler.ClientCertificateOptions = ClientCertificateOption.Manual;
        httpClientHandler.ClientCertificates.Add(clientCertificate);
        string url = $"{Configuration.FileService.Url}";

        using (HttpClient httpClient = new HttpClient(httpClientHandler))
        {
            httpClient.DefaultRequestHeaders.TransferEncodingChunked = true;
            MultipartFormDataContent multiForm = new MultipartFormDataContent();

            using (FileStream fs = System.IO.File.OpenRead(Path.Combine(Configuration.FileService.InputFilesPath, file.FileName)))
            {
                multiForm.Add(new StreamContent(fs), "file", file.FileName);

                using (HttpResponseMessage response = await httpClient.PostAsync(url, multiForm))
                {
                    response.EnsureSuccessStatusCode();
                    return true;
                }
            }
        }
    }
}

抛出的异常如下

System.Net.Http.HttpRequestException: Error while copying content to a stream.
 ---> System.IO.IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host..
 ---> System.Net.Sockets.SocketException (10054): An existing connection was forcibly closed by the remote host.
   --- End of inner exception stack trace ---
   at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.ThrowException(SocketError error, CancellationToken cancellationToken)
   at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.System.Threading.Tasks.Sources.IValueTaskSource.GetResult(Int16 token)
   at System.Net.Security.SslStream.<WriteSingleChunk>g__CompleteAsync|210_1[TWriteAdapter](ValueTask writeTask, Byte[] bufferToReturn)
   at System.Net.Security.SslStream.WriteAsyncChunked[TWriteAdapter](TWriteAdapter writeAdapter, ReadOnlyMemory`1 buffer)
   at System.Net.Security.SslStream.WriteAsyncInternal[TWriteAdapter](TWriteAdapter writeAdapter, ReadOnlyMemory`1 buffer)
   at System.Net.Http.HttpConnection.WriteAsync(ReadOnlyMemory`1 source)
   at System.Net.Http.HttpConnection.ChunkedEncodingWriteStream.<WriteAsync>g__WriteChunkAsync|2_0(HttpConnection connection, ReadOnlyMemory`1 buffer)
   at System.IO.Stream.CopyToAsyncInternal(Stream destination, Int32 bufferSize, CancellationToken cancellationToken)
   at System.Net.Http.HttpContent.CopyToAsyncCore(ValueTask copyTask)
   --- End of inner exception stack trace ---
   at System.Net.Http.HttpContent.CopyToAsyncCore(ValueTask copyTask)
   at System.Net.Http.MultipartContent.SerializeToStreamAsyncCore(Stream stream, TransportContext context, CancellationToken cancellationToken)
   at System.Net.Http.HttpContent.CopyToAsyncCore(ValueTask copyTask)
   at System.Net.Http.HttpConnection.SendRequestContentAsync(HttpRequestMessage request, HttpContentWriteStream stream, CancellationToken cancellationToken)
   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.DiagnosticsHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.HttpClient.FinishSendAsyncBuffered(Task`1 sendTask, HttpRequestMessage request, CancellationTokenSource cts, Boolean disposeCts)

使用 Wireshark 我得到以下流量,并且似乎在 FIN,ACK 之后连接没有正常关闭

Wireshark trace

任何帮助将不胜感激。

稍后编辑

感谢您的所有帮助。

看来我的问题是由 .NET Core 3.1 中仍然存在的 SocketsHttpHandler 实现中的错误产生的(尽管他们建议它已在 3.1 中修复),我发现这里描述了 https://github.com/dotnet/runtime/issues/27415

解决方案是添加

AppContext.SetSwitch("System.Net.Http.UseSocketsHttpHandler", false);

在方法的开头。

【问题讨论】:

  • 在异常本身An existing connection was forcibly closed by the remote host..
  • 尝试增加连接超时,所以如果它需要更多时间来解析,那么连接将不会关闭,但在我看来,这里的问题可能是解析文件时出现的异常,您需要验证,强制关闭 HttpClient

标签: c# httpclient


【解决方案1】:

语句“An existing connection was forcibly closed by the remote host”告诉我们问题出在请求的接收端。如果我们有一个格式错误的请求,它会给所有文件一个错误,但是,我们的情况是不同的。也许,接收端强制执行了 file size limitrequest timeout 不允许请求成功完成。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-08-19
    • 2023-01-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多