iis 连接重置异常:远程主机在为大文件调用Rest API时强制关闭了现有连接

ahy6op9u  于 2022-11-12  发布在  其他
关注(0)|答案(4)|浏览(169)

我有一个C# WebAPI,可以让用户上传文件。这个应用程序在http上运行得很好。但是当我为我的API添加https时,我发现它在小文件上运行得很好,但是对于大文件(〉60MB),请求只会等待2分钟,然后就失败了。在查看服务器日志后,我发现了这个异常:

Microsoft.AspNetCore.Connections.ConnectionResetException: 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.
   at Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal.SocketAwaitableEventArgs.<GetResult>g__ThrowSocketException|5_0(SocketError e)
   at Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal.SocketAwaitableEventArgs.GetResult(Int16 token)
   at Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal.SocketConnection.DoReceive()
   --- End of inner exception stack trace ---
   at System.IO.Pipelines.Pipe.GetReadResult(ReadResult& result)
   at System.IO.Pipelines.Pipe.GetReadAsyncResult()
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.Http1ContentLengthMessageBody.ReadAsyncInternal(CancellationToken cancellationToken)
   at System.Runtime.CompilerServices.PoolingAsyncValueTaskMethodBuilder`1.StateMachineBox`1.System.Threading.Tasks.Sources.IValueTaskSource<TResult>.GetResult(Int16 token)
   at System.IO.Pipelines.PipeReader.CopyToAsyncCore[TStream](TStream destination, Func`4 writeAsync, CancellationToken cancellationToken)
   at Infrastructure.LocalStorage.Domain.UploadFile.UploadChunkFileStreamService.SaveFileChunkAsync(UploadFileCommand command, String fileChunkPath)

更疯狂的是,它在一个服务器上运行良好(我们在开发环境中设置了https),但在另一个服务器上就不行了。在这两种情况下,我们都使用了IIS。有什么办法可以解决这个问题吗?我是否遗漏了HTTPS的IIS配置?
注意事项:

  • 我们已经使uploadReadAheadSize更大以避免413错误。
  • 我添加了以下代码到我的服务器上的建议这个post(然而,这是一个SocketException而不是ConnectionResetException,虽然消息是相同的)
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12
  • 文件正由React应用程序从前端上传。

注意2:当我减少上传到服务器的数据块数量时,它工作正常,没有任何错误。现在我一次上传2个数据块。

pkwftd7m

pkwftd7m1#

如果你要发布大量的数据,你需要在Web.config中指定请求限制、长度和最大执行时间,答案来自this thread

<requestLimits maxAllowedContentLength="2147483647" />
<httpRuntime targetFramework="4.6.1" maxRequestLength="2147483647" executionTimeout="1600" requestLengthDiskThreshold="2147483647" />

此外,this详细说明了该设置。

txu3uszq

txu3uszq2#

对于IIS托管的应用程序,重要的是在web.config上设置requestLimits标记以获取更多信息:https://learn.microsoft.com/en-us/iis/configuration/system.webserver/security/requestfiltering/requestlimits/和堆栈中溢出(已应答)maxRequestLength for .Net 4.5.1 framework
同时增加web.config文件上requesttimeout:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <system.webServer>
    <handlers>
      <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified"/>
    </handlers>
    <aspNetCore requestTimeout="00:15:00"  processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" />
  </system.webServer>
</configuration>
xfb7svmp

xfb7svmp3#

这有两个部分:
1.配置.net WebAPI后端应用程序。上面的答案涵盖了app.config设置以及所需的C#调用。
1.将Web服务器配置为接受大于X MB的文件
有时也会出现第3、4、5或6部分,但这不太可能
1.如果你使用的是基于云的Azure Web应用,则需要高级Web应用服务计划。基本Web应用服务计划将文件限制为60 MB。
1.在前端调用者代码和后端服务器之间的任何防火墙、代理等都可能由于大小或超时而丢弃请求
1.如果您同时上传多个文件块,Web服务器可能会耗尽资源并发生阻塞。
1.由于数据量的原因,C#后端服务器上出现了某种死锁、文件写入阻塞或内存不足。我会显式清除任何C#字节数组、关闭任何文件、关闭并处理任何流等,并将变量设置为null。C#垃圾收集器最终会这样做,但最好强制将它们清理干净。

m1m5dgzv

m1m5dgzv4#

“通信端例外状况(10054):远程主机强制关闭了现有的连接”意味着客户端异常断开连接。例如,如果客户端进程在连接过程中退出,则可能发生这种情况。
如果客户端在上载请求主体的过程中断开连接,则可能导致HttpContext.Request.Body.ReadAsync()抛出导致更高严重性的日志,这是非常罕见的。
如果你只是想修复这个问题,你可以尝试启用缓冲并在try/catch中清空整个请求主体。在catch中,你可以记录你想要的任何严重性的问题。如果你成功读取了整个主体,你可以将request.Body.Position设置回零,然后从你的主应用再次读取,而不用担心会看到IOException。
为请求主体启用多个读取的建议方法。下面是一个在自定义ASP.NET中间件的InvokeAsync()方法中使用的示例:

public async Task InvokeAsync(HttpContext context, RequestDelegate next)
{
context.Request.EnableBuffering();

// Leave the body open so the next middleware can read it.
using (var reader = new StreamReader(
    context.Request.Body,
    encoding: Encoding.UTF8,
    detectEncodingFromByteOrderMarks: false,
    bufferSize: bufferSize,
    leaveOpen: true))
    {
    var body = await reader.ReadToEndAsync();
    // Do some processing with body…

    // Reset the request body stream position so the next middleware can read it
    context.Request.Body.Position = 0;
    }

    // Call the next delegate/middleware in the pipeline
    await next(context);
    }

后备FileBufferingReadStream首先使用特定大小的内存流,然后福尔斯临时文件流。默认情况下,内存流的大小为30 KB。还有其他EnableBuffering()重载,它们允许指定不同的阈值和/或总大小限制:

public static void EnableBuffering(this HttpRequest request, int bufferThreshold)
public static void EnableBuffering(this HttpRequest request, long bufferLimit)
public static void EnableBuffering(this HttpRequest request, int bufferThreshold, long bufferLimit)

我希望这对解决问题有帮助。

相关问题