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

如何在Azure App Service托管的ASP.NET Web API中暴露Content-Disposition响应头?

在Azure App Service中暴露Content-Disposition响应头的解决方案

问题背景

我开发了一个基于.NET Web API的文件下载应用,客户端用NSwag生成代码。本地运行时一切正常,但部署到Azure App Service后,客户端死活拿不到下载文件名。

客户端本来依赖Content-Disposition响应头获取文件名,这个头是API控制器返回FileContentResult时自动添加的。但Content-Disposition不属于CORS安全响应头,必须通过Access-Control-Expose-Headers头明确允许,客户端才能访问它。

本地环境里,我在Startup中配置的CORS策略(用WithExposedHeaders("Content-Disposition"))能正常生效,响应里同时有Content-Disposition和Access-Control-Expose-Headers头。但一部署到Azure,响应里只有正确的Content-Disposition头,Access-Control-Expose-Headers头就消失了,导致客户端读不到文件名。

我试过清空Azure App Service上的CORS设置(怕它覆盖应用内的策略),没用;也试过在Azure某个设置里加Content-Disposition,同样没效果,而且这个设置只有某篇Stack Overflow提到,没其他参考。另外,Azure容器应用有专门的暴露头配置,但App Service的CORS配置里根本没这个选项。

相关代码

ConfigureServices 配置

public void ConfigureServices(IServiceCollection services)
{
    services.AddCors(options =>
    {
        options.AddDefaultPolicy(builder =>
        {
            builder.AllowAnyHeader();
            builder.AllowAnyMethod();
            builder.WithExposedHeaders("Content-Disposition");
        });
    });
}

Configure 配置

public void Configure(IApplicationBuilder app)
{
    app.UseRouting();

    app.UseCors();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
    });
}

API控制器代码

[HttpGet]
[Route("getfile")]
public async Task<ActionResult> GetFile(long id)
{
    var file =  await _fileService.GetFile(id);

    return File(file.Content, file.MimeType, file.Name);
}

解决方案

方法1:控制器内手动添加响应头

有时候Azure的中间件会拦截或覆盖CORS头,直接在控制器的响应里手动加Access-Control-Expose-Headers,绕过潜在的策略问题:

修改GetFile方法:

[HttpGet]
[Route("getfile")]
public async Task<ActionResult> GetFile(long id)
{
    var file = await _fileService.GetFile(id);
    var result = File(file.Content, file.MimeType, file.Name);
    // 手动添加暴露头
    Response.Headers.Add("Access-Control-Expose-Headers", "Content-Disposition");
    return result;
}

方法2:禁用Azure的CORS预检代理

Azure App Service可能有默认的CORS代理行为,添加应用设置禁用它:

  1. 打开Azure门户,进入你的App Service
  2. 跳转到配置 > 应用设置
  3. 新增一个设置:
    • 名称:WEBSITE_DISABLE_CORS_PREFLIGHT
    • 值:true
  4. 保存设置后重启App Service

这个设置会让Azure的前端代理不再处理CORS预检请求,确保应用内的CORS策略完全生效。

方法3:全局自定义中间件添加头

如果需要所有接口都生效,可以写个自定义中间件,给所有响应加上暴露头:

public class ExposeHeadersMiddleware
{
    private readonly RequestDelegate _next;

    public ExposeHeadersMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task InvokeAsync(HttpContext context)
    {
        // 在响应发送前插入头
        context.Response.OnStarting(() =>
        {
            if (!context.Response.Headers.ContainsKey("Access-Control-Expose-Headers"))
            {
                context.Response.Headers.Add("Access-Control-Expose-Headers", "Content-Disposition");
            }
            return Task.CompletedTask;
        });

        await _next(context);
    }
}

然后在Configure方法里注册这个中间件(要放在UseCors之前):

public void Configure(IApplicationBuilder app)
{
    app.UseRouting();

    app.UseMiddleware<ExposeHeadersMiddleware>();

    app.UseCors();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
    });
}

验证步骤

部署修改后的代码或设置后,用浏览器开发者工具检查:

  1. 发起文件下载请求
  2. 查看网络标签里的响应头
  3. 确认同时存在Content-Disposition和Access-Control-Expose-Headers: Content-Disposition
  4. 测试客户端是否能正常读取文件名

内容的提问来源于stack exchange,提问作者Cristian Sanchez

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 14:56:17