azure - 在 Azure 应用服务上运行的 ASP.NET Core 3.1 应用针对 1.6 MB json 负载抛出 EPIPE 错误

标签 azure asp.net-core azure-web-app-service

我在 Azure 应用服务上部署了一个简单的 ASP.NET Core 3.1 应用程序,并配置了 .NET Core 3.1 运行时。我的一个端点预计会收到一个带有单个“数据”属性的简单 JSON 有效负载,该属性是文件的 Base64 编码字符串。它可能会很长,当 JSON 有效负载为 1.6 MB 时,我遇到了以下问题。

在我的本地工作站上,当我从 Postman 调用 API 时,一切都按预期工作,达到了 Controller 操作方法中的断点,填充了数据,一切都很好 - 仅当我部署时(通过 Azure DevOps CICD Pipelines) ) 将应用程序添加到 Azure 应用服务。每当尝试从 Postman 调用已部署的 API 时,都不会收到 HTTP 响应,但会显示:“错误:写入 EPIPE”。

我尝试修改 web.config 以包含 maxRequestLength 和 maxAllowedContentLength 属性:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <location path="." inheritInChildApplications="false">
      <system.web>
          <httpRuntime maxRequestLength="204800" ></httpRuntime>
          </system.web>
    <system.webServer>
            <security>
        <requestFiltering>          
            <requestLimits maxAllowedContentLength="419430400" />
        </requestFiltering>
    </security>
      <handlers>
        <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" />
      </handlers>
      <aspNetCore processPath="dotnet" arguments=".\MyApp.API.dll" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" hostingModel="inprocess" />
    </system.webServer>
  </location>
</configuration>

在应用程序的代码中,我已添加到 Startup.cs:

services.Configure<IISServerOptions>(options => {
    options.MaxRequestBodySize = int.MaxValue;
});

在 Program.cs 中,我添加了:

.UseKestrel(options => { options.Limits.MaxRequestBodySize = int.MaxValue; })

在 Controller 中,我尝试了这两个属性:[DisableRequestSizeLimit]、[RequestSizeLimit(40000000)]

但是,到目前为止,什么都不起作用 - 我很确定它必须是在应用服务本身上配置的东西,而不是在我的代码中,因为本地一切都正常。然而,到目前为止,web.config 中没有任何帮助

最佳答案

这与以下事实有关:在我的应用服务中,我必须在配置中允许传入客户端证书 - 结果客户端证书和大型有效负载在 IIS 中不能很好地混合(显然已经有十多年了) : https://learn.microsoft.com/en-us/archive/blogs/waws/posting-a-large-file-can-fail-if-you-enable-client-certificates

上述博客文章中提出的解决方法都没有解决我的问题,因此我必须解决方法:我创建了一个带有消耗计划的 Azure Function(仍使用 .NET Core 3.1 作为运行时堆栈),它能够接收大负载和传入的客户端证书(我猜它在幕后没有使用 IIS?)。

在我的原始后端中,我将原始 API 的路由添加到应用服务的“证书排除路径”,以免最终因“错误:写入 EPIPE”而陷入等待和超时。

我已使用托管标识在我的应用服务和新的 Azure Functions 之间进行身份验证(通过函数中的系统分配标识)。

Azure 函数获取收到的证书,并将其添加到 JSON 正文中的新“证书”属性中,位于原始“数据”属性旁边,因此我的自定义 SSL 验证可以保留在应用服务上,但证书不是从 X-ARR-ClientCert header 中获取,而是从接收到的有效负载的“证书”属性中获取。

功能:

#r "Newtonsoft.Json"
using System.Net;
using System.IO;
using System.Net.Http;
using System.Text;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Primitives;
using Newtonsoft.Json;
using System.Security.Cryptography.X509Certificates;

private static HttpClient httpClient = new HttpClient();

public static async Task<IActionResult> Run(HttpRequest req, ILogger log)
{
    var requestBody = string.Empty;
    using (var streamReader =  new StreamReader(req.Body))
    {
        requestBody = await streamReader.ReadToEndAsync();
    }

    dynamic deserializedPayload = JsonConvert.DeserializeObject(requestBody);
    var data = deserializedPayload?.data;
    
    var originalUrl = $"https://original-backend.azurewebsites.net/api/inbound";
    var certificateString = string.Empty;

    StringValues cert;
    if (req.Headers.TryGetValue("X-ARR-ClientCert", out cert))
    {
        certificateString = cert;
    }

    var newPayload = new {
        data = data,
        certificate = certificateString
    };

    var response = await httpClient.PostAsync(
        originalUrl,
        new StringContent(JsonConvert.SerializeObject(newPayload), Encoding.UTF8, "application/json"));

    var responseContent = await response.Content.ReadAsStringAsync();

    try
    {
        response.EnsureSuccessStatusCode();
        return new OkObjectResult(new { message = "Forwarded request to the original backend" });
    }
    catch (Exception e)
    {
        return new ObjectResult(new { response = responseContent, exception = JsonConvert.SerializeObject(e)})
        {
            StatusCode = 500
        };
    }
}

关于azure - 在 Azure 应用服务上运行的 ASP.NET Core 3.1 应用针对 1.6 MB json 负载抛出 EPIPE 错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69944201/

相关文章:

azure - 当范围不是 Azure AD 中的图形 API 时,如何添加自定义声明并检索相同的声明作为 access_token 的一部分?

.net - nuget 的程序集被 GAC 的程序集覆盖

c# - 使用 Azure 应用服务和 Facebook 身份配置 ASP.NET Core Web 应用程序时出错

c# - 如何在 ASP.NET Core Web API 中配置 JSON 格式缩进

c# - 如何在 ASP.NET Core 2.2 中使用来自不同托管项目的共享 SignalR Hub

node.js - 我有一个非常基本的世界 koajs Web 应用程序,我需要在 azure 上进行测试

azure - 如何通过私有(private) DNS 名称从虚拟网络中的应用服务访问 Azure VM?

azure - 如何使用服务主体连接到 Azure?

Azure CLI - 删除订阅?

c# - 如何在 ASP.NET Core 2.1 中使用角色?