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

.NET Core 2 MVC接口设Accept为text/csv时返回415错误求助

嘿,我来帮你搞定这个POST请求返回415 Unsupported Media Type的问题!你遇到的这个错误主要有两个核心原因:一是ASP.NET Core默认没配置能解析text/csv格式请求体的输入格式化器,二是框架本身也没有内置CSV输出的处理逻辑。下面一步步给你捋清楚解决方案:

先搞对请求头的用法(避免低级错误)

如果你只是希望接口返回CSV文件,但请求体还是JSON格式,那完全不需要设置Content-Type: text/csv!Content-Type是告诉后端「我的请求体是什么格式」,而Accept才是告诉后端「我想要什么格式的响应」。要是你错误地把Content-Type设为text/csv,但实际发的是JSON请求体,后端肯定懵圈,直接返回415。

只有当你的请求体真的是CSV格式时,才需要设置Content-Type: text/csv——这时候咱们再去配置输入格式化器。

配置CSV输出格式化器(实现返回CSV文件)

ASP.NET Core 2 MVC没有自带CSV输出的处理能力,所以得咱们自己写一个简单的格式化器:

1. 创建CSV输出格式化器类

using Microsoft.AspNetCore.Mvc.Formatters;
using System.Reflection;
using System.Text;

public class CsvOutputFormatter : TextOutputFormatter
{
    public CsvOutputFormatter()
    {
        SupportedMediaTypes.Add("text/csv");
        SupportedEncodings.Add(Encoding.UTF8);
        SupportedEncodings.Add(Encoding.Unicode);
    }

    protected override bool CanWriteType(Type type)
    {
        // 这里根据你的实际返回类型调整,比如支持IEnumerable<T>或者特定模型
        return typeof(IEnumerable).IsAssignableFrom(type);
    }

    public override async Task WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding)
    {
        var response = context.HttpContext.Response;
        var buffer = new StringBuilder();

        // 假设你返回的是IEnumerable<YourModel>,这里替换成你实际的模型类
        var data = context.Object as IEnumerable<YourModel>;
        if (data == null) return;

        // 写CSV表头(用模型的属性名)
        var properties = typeof(YourModel).GetProperties(BindingFlags.Public | BindingFlags.Instance);
        buffer.AppendLine(string.Join(",", properties.Select(p => p.Name)));

        // 写数据行,注意处理包含逗号的字段(转义一下)
        foreach (var item in data)
        {
            var values = properties.Select(p => 
            {
                var val = p.GetValue(item)?.ToString();
                return val?.Contains(",") ? $"\"{val}\"" : val;
            });
            buffer.AppendLine(string.Join(",", values));
        }

        await response.WriteAsync(buffer.ToString(), selectedEncoding);
    }
}

2. 在Startup.cs里注册这个格式化器

打开Startup.cs,找到ConfigureServices方法,把CSV格式化器加到MVC配置里:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc(options =>
    {
        // 添加咱们自定义的CSV输出格式化器
        options.OutputFormatters.Add(new CsvOutputFormatter());
        // 把csv后缀和text/csv媒体类型关联起来(可选,但方便路由里指定格式)
        options.FormatterMappings.SetMediaTypeMappingForFormat("csv", "text/csv");
    })
    .SetCompatibilityVersion(CompatibilityVersion.Version_2_2); // 对应你的.NET Core 2版本
}

如果需要接收CSV格式的请求体(添加输入格式化器)

要是你的POST请求体真的是CSV格式,那还得加一个输入格式化器,让后端能解析这个CSV内容:

1. 创建CSV输入格式化器类

using Microsoft.AspNetCore.Mvc.Formatters;
using System.Reflection;
using System.Text;

public class CsvInputFormatter : TextInputFormatter
{
    public CsvInputFormatter()
    {
        SupportedMediaTypes.Add("text/csv");
        SupportedEncodings.Add(Encoding.UTF8);
        SupportedEncodings.Add(Encoding.Unicode);
    }

    protected override bool CanReadType(Type type)
    {
        // 支持解析为IEnumerable<YourModel>,替换成你实际的模型类
        return typeof(IEnumerable<YourModel>).IsAssignableFrom(type);
    }

    public override async Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context, Encoding encoding)
    {
        using var reader = new StreamReader(context.HttpContext.Request.Body, encoding);
        var content = await reader.ReadToEndAsync();

        var lines = content.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
        if (lines.Length == 0)
        {
            return await InputFormatterResult.SuccessAsync(new List<YourModel>());
        }

        var properties = typeof(YourModel).GetProperties(BindingFlags.Public | BindingFlags.Instance);
        var data = new List<YourModel>();

        // 跳过第一行表头(如果你的CSV有表头的话,要是没有就去掉这个循环)
        for (int i = 1; i < lines.Length; i++)
        {
            var values = lines[i].Split(',');
            var item = Activator.CreateInstance<YourModel>();

            for (int j = 0; j < properties.Length && j < values.Length; j++)
            {
                var value = values[j].Trim('"'); // 去掉转义的引号
                if (!string.IsNullOrEmpty(value))
                {
                    properties[j].SetValue(item, Convert.ChangeType(value, properties[j].PropertyType));
                }
            }

            data.Add(item);
        }

        return await InputFormatterResult.SuccessAsync(data);
    }
}

2. 在Startup.cs里注册输入格式化器

还是在ConfigureServices的MVC配置里,加上输入格式化器:

services.AddMvc(options =>
{
    options.InputFormatters.Add(new CsvInputFormatter()); // 添加CSV输入格式化器
    options.OutputFormatters.Add(new CsvOutputFormatter());
    options.FormatterMappings.SetMediaTypeMappingForFormat("csv", "text/csv");
})
.SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

最后调整控制器动作

确保你的控制器动作保留[Produces("application/json", "text/csv")]特性,并且返回对应的数据类型:

[HttpPost]
[Produces("application/json", "text/csv")]
public async Task<IActionResult> YourAction([FromBody] YourInputModel input) 
// 如果是接收CSV请求体,就改成 [FromBody] IEnumerable<YourModel> input
{
    // 你的业务逻辑,获取要返回的数据
    var resultData = await GetYourDataAsync(input);
    
    // 要是想直接触发文件下载,可以手动返回FileResult(可选,格式化器也能自动处理)
    if (Request.Headers["Accept"].Contains("text/csv"))
    {
        // 这里也可以用上面的格式化器逻辑生成CSV内容,或者直接让框架自动处理
        return Ok(resultData);
        // 或者手动生成后返回下载:
        // var csvContent = GenerateCsv(resultData);
        // return File(Encoding.UTF8.GetBytes(csvContent), "text/csv", "export.csv");
    }
    
    return Ok(resultData);
}

这样调整之后,当你设置Accept: text/csv(请求体是JSON的话,Content-Type保持application/json),接口就会返回CSV格式的响应;如果确实需要发送CSV请求体,添加输入格式化器后也能正常解析,不会再出现415错误啦!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 07:27:21