在 Azure 应用服务上运行的 ASP.NET Core 3.1 应用针对 1.6 MB json 有效负载引发 EPIPE 错误

Posted

技术标签:

【中文标题】在 Azure 应用服务上运行的 ASP.NET Core 3.1 应用针对 1.6 MB json 有效负载引发 EPIPE 错误【英文标题】:ASP.NET Core 3.1 app running on Azure App Service throwing EPIPE errors for 1.6 MB json payload 【发布时间】:2021-12-24 21:03:53 【问题描述】:

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

在我的本地工作站上,当我从 Postman 调用我的 API 时,一切都按预期工作,到达控制器操作方法中的断点,填充数据,一切都很好 - 只有当我部署时(通过 Azure DevOps CICD Pipelines ) 应用到 Azure 应用服务。每当尝试从 Postman 调用已部署的 API 时,都不会收到 HTTP 响应,而是:“Error: write 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; )

在控制器中,我尝试了以下两个属性:[DisableRequestSizeLimit]、[RequestSizeLimit(40000000)]

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

【问题讨论】:

【参考方案1】:

这与以下事实有关:https://docs.microsoft.com/en-us/archive/blogs/waws/posting-a-large-file-can-fail-if-you-enable-client-certificates

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

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

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

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

功能:

#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 应用服务上运行的 ASP.NET Core 3.1 应用针对 1.6 MB json 有效负载引发 EPIPE 错误的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Azure App Service 上运行的 ASP.NET Framework App 中禁用服务器 GC

增加在 Azure 上运行的 Dockerized ASP.NET Core 站点的最大上传大小限制?

Azure asp.net Web 应用程序尝试连接到 Oracle 运行时集成链接服务

ASP.NET Core Azure AD OpenID - 生产服务器上的令牌签名验证失败

在 ASP.NET Azure 网站上使用 Ghostscript.Net

在 Azure WebApps 中运行64位 Asp.net Core 应用