You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Azure App Service大文件上传报413及CORS错误,本地正常

问题描述

尝试向API发送包含70MiB二进制文件的multipart/form-data表单,上传完成时出现两个错误:

Access to XMLHttpRequest at 'https://api.contoso.com/v1/controller/upload' from origin 'https://www.contoso.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

POST https://api.contoso.com/v1/controller/upload net::ERR_FAILED 413 (Request Entity Too Large)

仅小文件(如5MiB)可上传成功,其他端点无CORS问题,本地运行时无此报错,控制器方法从未执行,"Uploading asset"日志未出现。

现有配置

ASP.NET Core 基础配置

builder.Services.Configure<KestrelServerOptions>(options =>
{
    options.Limits.MaxRequestBodySize = long.MaxValue;
    options.Limits.MaxRequestBufferSize = long.MaxValue;
});
builder.Services.Configure<FormOptions>(options =>
{
    options.MultipartBodyLengthLimit = 200 * 1024 * 1024; //200 MB
});
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();

//DB connection
//Blob storage connection
//Auth/JWT
//Services/DI

var app = builder.Build();
app.Logger.LogInformation("Starting...");

生产环境配置

app.Logger.LogInformation("Production mode");

app.UseCors(policyBuilder =>
{
    policyBuilder.SetIsOriginAllowed((origin) => {
        app.Logger.LogInformation("Origin of call: " + origin);

        return origin.Equals("https://contoso.com") || origin.Equals("https://www.contoso.com");
    })
    .AllowAnyHeader().AllowAnyMethod().WithExposedHeaders("App-Desktop"); 
});

//Allow access by the desktop app to these endpoints.
app.Use(async (context, next) =>
{
    if (context.Request.Headers.ContainsKey("App-Desktop"))
    {
        var path = context.Request.Path.Value?.ToLower() ?? "";

        app.Logger.LogInformation("Path of call from desktop app: " + path);

        if (path.StartsWith("/v1/blogs"))
            context.Response.Headers.Append("Access-Control-Allow-Origin", "*");
    }

    await next();
});

控制器方法

[HttpPost("upload")]
[Consumes("multipart/form-data")]
//[RequestSizeLimit(209_715_200)] //200Mib
[DisableRequestSizeLimit]
public async Task<IActionResult> UploadBinary(IFormFile file, [FromForm] BinaryRequest binary)
{
  _logger.LogInformation("Uploading asset: " + file.FileName);

  //...
}

补充优化后的配置(仍无效)

builder.Services.Configure<KestrelServerOptions>(options =>
{
    options.Limits.MaxRequestBodySize = long.MaxValue;
    options.Limits.MaxRequestBufferSize = long.MaxValue;
    options.Limits.MaxRequestHeadersTotalSize = int.MaxValue;
    options.Limits.MaxResponseBufferSize = long.MaxValue;
});
builder.Services.Configure<FormOptions>(options =>
{
    options.ValueLengthLimit = int.MaxValue;
    options.MultipartBodyLengthLimit = long.MaxValue;
    options.MultipartHeadersLengthLimit = int.MaxValue;
    options.BufferBodyLengthLimit = long.MaxValue;
    options.MemoryBufferThreshold = int.MaxValue;
});

Azure API Insights 日志

Request starting HTTP/1.1 OPTIONS https://api.contoso.com/v1/controller/upload - - -

Origin of call: https://www.contoso.com

CORS policy execution successful.

Request finished HTTP/1.1 OPTIONS https://api.contoso.com/v1/controller/upload - 204 - - 2.1230ms


原因分析与解决方案

核心原因

  1. 413错误根源:Azure App Service 层面的请求大小限制
    你已经配置了Kestrel和FormOptions的大小限制,但生产环境部署在Azure App Service时,默认POST请求大小限制为30MB,这个限制会在请求到达ASP.NET Core应用之前就被拦截,导致控制器方法根本不会执行。
  2. CORS错误的连锁反应
    Azure返回413错误时,没有在响应中添加Access-Control-Allow-Origin头,浏览器因此将这个错误额外解读为CORS问题,同时抛出两个错误。

解决方案

1. 调整Azure App Service的上传限制

  • 登录Azure门户,找到目标App Service实例
  • 进入配置 -> 常规设置
  • 在上传限制处设置大于70MB的数值(比如200MB)
  • 保存设置并重启App Service

2. 确保错误响应中包含CORS头

调整中间件顺序,让CORS中间件优先执行,并添加全局错误处理逻辑,保证异常场景下也能返回正确的CORS头:

// 优先注册CORS中间件
app.UseCors(policyBuilder =>
{
    policyBuilder.SetIsOriginAllowed((origin) => {
        app.Logger.LogInformation("Origin of call: " + origin);
        return origin.Equals("https://contoso.com") || origin.Equals("https://www.contoso.com");
    })
    .AllowAnyHeader().AllowAnyMethod().WithExposedHeaders("App-Desktop"); 
});

// 全局错误处理中间件,确保错误响应携带CORS头
app.Use(async (context, next) =>
{
    try
    {
        await next();
    }
    catch (Exception ex)
    {
        // 补全CORS头
        if (!context.Response.Headers.ContainsKey("Access-Control-Allow-Origin"))
        {
            var origin = context.Request.Headers["Origin"].FirstOrDefault();
            if (!string.IsNullOrEmpty(origin) && (origin.Equals("https://contoso.com") || origin.Equals("https://www.contoso.com")))
            {
                context.Response.Headers.Append("Access-Control-Allow-Origin", origin);
            }
        }
        // 自定义错误响应
        context.Response.StatusCode = StatusCodes.Status500InternalServerError;
        await context.Response.WriteAsync("服务器内部错误");
    }
});

// 再注册桌面应用相关中间件
app.Use(async (context, next) =>
{
    if (context.Request.Headers.ContainsKey("App-Desktop"))
    {
        var path = context.Request.Path.Value?.ToLower() ?? "";
        app.Logger.LogInformation("Path of call from desktop app: " + path);
        if (path.StartsWith("/v1/blogs"))
            context.Response.Headers.Append("Access-Control-Allow-Origin", "*");
    }
    await next();
});

3. 验证配置

重启App Service后,再次尝试上传70MiB文件,检查Azure API Insights日志,确认POST请求能到达控制器(出现"Uploading asset"日志)。


内容的提问来源于stack exchange,提问作者Nicke Manarin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 06:04:57