Minimal API生产环境下无效JSON请求无法自定义异常处理的问题
原因分析
ASP.NET Core在生产环境下,默认通过ApiBehaviorOptions自动拦截模型绑定/JSON解析类错误(比如你遇到的无效JSON),直接返回标准化的400响应,不会将这类异常传递到你注册的UseExceptionHandler全局异常处理器中。而开发环境为了便于调试,会跳过这个自动拦截,让异常能被全局处理器捕获,所以你能看到自定义的响应内容。
解决方法
以下几种方式可以让你在生产环境中控制无效JSON输入的响应:
1. 禁用默认的模型状态无效过滤器
通过配置ApiBehaviorOptions关闭自动拦截,让模型绑定错误流入全局异常处理器:
var builder = WebApplication.CreateBuilder(args); // 添加配置禁用默认过滤器 builder.Services.Configure<ApiBehaviorOptions>(options => { options.SuppressModelStateInvalidFilter = true; }); var app = builder.Build(); // 你的全局异常处理器代码保持不变 app.UseExceptionHandler((exceptionApp) => { exceptionApp.Run(async context => { context.Response.ContentType = MediaTypeNames.Text.Plain; var feature = context.Features.Get<IExceptionHandlerPathFeature>(); if (feature?.Error is BadHttpRequestException ex) { context.Response.StatusCode = 400; var message = (ex.InnerException is JsonException) ? "The request body is an invalid JSON" : "Bad Request"; await context.Response.WriteAsync(message); } else { context.Response.StatusCode = 500; await context.Response.WriteAsync("There is a problem occured"); } }); }); app.MapPost("/models", (Model model) => Results.Created(string.Empty, model)); app.Run();
2. 自定义模型状态错误响应
如果不想完全禁用默认拦截,可以直接定制模型状态错误的返回内容,更精准地处理JSON解析错误:
var builder = WebApplication.CreateBuilder(args); builder.Services.Configure<ApiBehaviorOptions>(options => { options.InvalidModelStateResponseFactory = context => { // 检查是否存在JSON解析异常 var jsonException = context.ModelState.Values .SelectMany(v => v.Errors) .Select(e => e.Exception) .OfType<JsonException>() .FirstOrDefault(); if (jsonException != null) { return Results.Text( "The request body is an invalid JSON", statusCode: 400, contentType: MediaTypeNames.Text.Plain); } // 其他模型绑定错误返回默认的BadRequest响应 return Results.BadRequest(context.ModelState); }; }); var app = builder.Build(); // 全局异常处理器仍可处理其他非模型绑定类异常 app.UseExceptionHandler(...); app.MapPost("/models", (Model model) => Results.Created(string.Empty, model)); app.Run();
3. 提前捕获JSON解析异常
注册一个前置中间件,直接捕获JSON解析阶段抛出的BadHttpRequestException,确保在生产环境下能拦截到:
var app = builder.Build(); // 这个中间件要放在路由映射和异常处理器之前 app.Use(async (context, next) => { try { await next(); } catch (BadHttpRequestException ex) { context.Response.ContentType = MediaTypeNames.Text.Plain; context.Response.StatusCode = 400; var message = (ex.InnerException is JsonException) ? "The request body is an invalid JSON" : "Bad Request"; await context.Response.WriteAsync(message); } }); app.UseExceptionHandler(...); // 保留处理其他异常 app.MapPost("/models", (Model model) => Results.Created(string.Empty, model)); app.Run();
内容的提问来源于stack exchange,提问作者Farzan Hajian
相关产品推荐
相关产品推荐

