我在 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/