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

ASP.NET Core Minimal API中如何为415错误返回JSON响应体

解决ASP.NET Core Minimal API无Content-Type头返回415无响应体问题

问题根源

当请求未携带Content-Type头时,ASP.NET Core会在模型绑定阶段直接返回415(Unsupported Media Type)状态码,这个过程没有抛出异常,而是由框架内部直接生成了空响应体。由于UseExceptionHandler仅处理未捕获的异常,因此无法拦截这个场景。

解决方案

可以通过以下几种方式自定义415错误的响应内容:

方法1:使用UseStatusCodePages全局处理状态码

这个方法可以捕获所有返回415状态码的请求,统一返回自定义JSON响应:

修改Program.cs的中间件顺序,在UseExceptionHandler之前添加UseStatusCodePages:

using System.Runtime.CompilerServices;
using Microsoft.AspNetCore.Mvc;

[assembly: InternalsVisibleTo("TestProject1")]

var builder = WebApplication.CreateBuilder(args);

builder.Services.Configure<RouteHandlerOptions>(o => o.ThrowOnBadRequest = true);
builder.Services.AddProblemDetails(); // 可选,用于生成符合RFC规范的问题详情

var app = builder.Build();

// 处理415等状态码的自定义响应
app.UseStatusCodePages(async context =>
{
    var response = context.HttpContext.Response;

    if (response.StatusCode == StatusCodes.Status415UnsupportedMediaType)
    {
        response.ContentType = "application/json";
        await response.WriteAsJsonAsync(new 
        {
            type = "https://tools.ietf.org/html/rfc7231#section-6.5.13",
            title = "Unsupported Media Type",
            status = 415,
            detail = "请求缺少Content-Type头,该端点需要携带application/json类型的请求体。",
            instance = context.HttpContext.Request.Path
        });
    }
});

app.UseExceptionHandler(handlerApp => handlerApp.Run(async context =>
{
    context.Response.StatusCode = 400;
    context.Response.ContentType = "application/json";
    await context.Response.WriteAsJsonAsync(new 
    {
        error = "服务器错误",
        message = "发生了未预期的异常。"
    });
}));

app.MapPost("/hi", ([FromBody] Request request) => "Hello World!");
app.MapPost("/throwerror", ([FromBody] Request request) => throw new Exception("Ouch"));

app.Run();

record Request(int Id);

方法2:自定义中间件精准拦截无Content-Type的请求

如果只想针对带请求体的方法(如POST/PUT)拦截无Content-Type的情况,可以添加自定义中间件:

app.Use(async (context, next) =>
{
    // 仅针对POST/PUT等包含请求体的方法检查
    if ((context.Request.Method == HttpMethods.Post || context.Request.Method == HttpMethods.Put)
        && string.IsNullOrEmpty(context.Request.ContentType))
    {
        context.Response.StatusCode = StatusCodes.Status415UnsupportedMediaType;
        context.Response.ContentType = "application/json";
        await context.Response.WriteAsJsonAsync(new 
        {
            error = "Unsupported Media Type",
            message = "必须提供Content-Type头,建议使用application/json。"
        });
        return;
    }

    await next();
});

// 后续中间件...
app.UseExceptionHandler(...);
app.MapPost(...);

方法3:端点过滤器针对特定端点处理

如果只需要给部分端点添加检查,可以使用端点过滤器:

var contentTypeFilter = new EndpointFilterDelegate(async (context, next) =>
{
    if (string.IsNullOrEmpty(context.HttpContext.Request.ContentType))
    {
        context.HttpContext.Response.StatusCode = StatusCodes.Status415UnsupportedMediaType;
        context.HttpContext.Response.ContentType = "application/json";
        await context.HttpContext.Response.WriteAsJsonAsync(new 
        {
            error = "缺少Content-Type头",
            message = "该端点需要携带Content-Type头。"
        });
        return Results.StatusCode(415);
    }

    return await next(context);
});

app.MapPost("/hi", ([FromBody] Request request) => "Hello World!")
   .AddEndpointFilter(contentTypeFilter);

修改测试用例

针对第一个测试,调整断言以匹配自定义的JSON响应:

[TestMethod]
public async Task TestHiRespondsWithJsonErrorOnNoContentType()
{
    var factory = new WebApplicationFactory<Program>();
    var client = factory.CreateClient();
    var response = await client.PostAsync("/hi", 
        new StringContent("{ \"Id\": 123 }", Encoding.UTF8));
    
    Assert.AreEqual(HttpStatusCode.UnsupportedMediaType, response.StatusCode);
    Assert.AreEqual("application/json", response.Content.Headers.ContentType?.MediaType);
    
    var error = await response.Content.ReadFromJsonAsync<dynamic>();
    Assert.AreEqual("Unsupported Media Type", error.title);
    Assert.AreEqual(415, error.status);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 21:18:27