如何自定义ASP.NET Core Web API(.NET8)与NSwag的错误响应体
解决.NET Core 8.0中JSON语法错误响应格式不一致的问题
核心原因
请求JSON语法错误属于请求体解析阶段的异常,发生在ASP.NET Core模型绑定之前,此时框架会直接生成默认400响应,不会触发常规的ExceptionMiddleware(因为中间件链路中异常未被抛出,或响应已开始构建)。
解决思路与实现方案
1. 替换默认JSON输入格式化器(推荐)
由于你使用Newtonsoft.Json,可自定义NewtonsoftJsonInputFormatter捕获解析异常,返回自定义格式响应:
- 创建自定义格式化器继承
NewtonsoftJsonInputFormatter:
public class CustomNewtonsoftJsonInputFormatter : NewtonsoftJsonInputFormatter { public CustomNewtonsoftJsonInputFormatter(ILogger logger, JsonSerializerSettings serializerSettings, ArrayPool<char> charPool, ObjectPoolProvider objectPoolProvider, MvcOptions options, MvcNewtonsoftJsonOptions jsonOptions) : base(logger, serializerSettings, charPool, objectPoolProvider, options, jsonOptions) { } public override async Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context) { try { return await base.ReadRequestBodyAsync(context); } catch (JsonReaderException ex) { // 构造与OpenAPI规范一致的自定义错误响应体 var errorResponse = new CustomErrorResponse { StatusCode = StatusCodes.Status400BadRequest, Message = "请求JSON格式错误", Details = ex.Message }; context.HttpContext.Response.StatusCode = StatusCodes.Status400BadRequest; await context.HttpContext.Response.WriteAsJsonAsync(errorResponse); return InputFormatterResult.Success(null); } } }
- 在Program.cs中替换默认格式化器:
builder.Services.AddControllers() .AddNewtonsoftJson(options => { // 保留你的Newtonsoft.Json配置,比如驼峰命名等 options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); }) .AddMvcOptions(options => { // 移除默认的NewtonsoftJsonInputFormatter var defaultFormatter = options.InputFormatters.OfType<NewtonsoftJsonInputFormatter>().FirstOrDefault(); if (defaultFormatter != null) { options.InputFormatters.Remove(defaultFormatter); // 注册自定义格式化器 var serviceProvider = builder.Services.BuildServiceProvider(); options.InputFormatters.Add(new CustomNewtonsoftJsonInputFormatter( serviceProvider.GetRequiredService<ILogger<NewtonsoftJsonInputFormatter>>(), defaultFormatter.SerializerSettings, serviceProvider.GetRequiredService<ArrayPool<char>>(), serviceProvider.GetRequiredService<ObjectPoolProvider>(), options, serviceProvider.GetRequiredService<IOptions<MvcNewtonsoftJsonOptions>>().Value )); } });
2. 使用IStartupFilter拦截响应
若不想替换格式化器,可通过IStartupFilter在响应发送前修改内容:
- 创建自定义StartupFilter:
public class ErrorResponseStartupFilter : IStartupFilter { public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next) { return app => { app.Use(async (context, nextMiddleware) => { // 先执行后续中间件,获取原始响应 await nextMiddleware(); // 仅处理JSON请求的400错误 if (context.Response.StatusCode == StatusCodes.Status400BadRequest && context.Request.ContentType?.Contains("application/json") == true) { // 读取原始响应内容 context.Response.Body.Seek(0, SeekOrigin.Begin); var originalContent = await new StreamReader(context.Response.Body).ReadToEndAsync(); context.Response.Body.Seek(0, SeekOrigin.Begin); // 判断是否为框架默认的JSON解析错误响应 if (!string.IsNullOrEmpty(originalContent) && originalContent.Contains("\"errors\":{\"\":[")) { // 构造自定义错误响应 var errorResponse = new CustomErrorResponse { StatusCode = StatusCodes.Status400BadRequest, Message = "请求JSON格式错误", Details = "JSON语法不符合规范,请检查后重试" }; // 重置响应并写入自定义内容 context.Response.ContentLength = null; context.Response.ContentType = "application/json"; await context.Response.WriteAsJsonAsync(errorResponse); } } }); next(app); }; } }
- 在Program.cs中注册:
builder.Services.AddTransient<IStartupFilter, ErrorResponseStartupFilter>();
3. 禁用默认模型绑定错误响应(补充方案)
关闭框架自动生成的模型绑定错误,再通过全局ActionFilter处理,但对JSON解析错误的覆盖性不如前两种:
builder.Services.Configure<ApiBehaviorOptions>(options => { options.SuppressModelStateInvalidFilter = true; });
添加全局ActionFilter检查模型状态,针对性处理空键的模型错误(JSON解析错误的特征),返回自定义响应。
关键注意事项
- 确保
CustomErrorResponse类的结构与OpenAPI规范定义的错误响应完全一致,保证NSwag生成的文档匹配。 - 测试时需发送确有语法错误的JSON(比如缺失引号、逗号错误),验证响应格式是否符合预期。
内容的提问来源于stack exchange,提问作者Frank
相关产品推荐
相关产品推荐

