.NET Core 6 API:如何捕获请求体格式错误引发的自动HTTP 400响应
.NET Core 6 API捕获自动返回的400错误并记录
问题描述
以下是一段.NET Core 6 API的接口代码:
[ProducesResponseType(StatusCodes.Status400BadRequest)] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] [ProducesResponseType(StatusCodes.Status500InternalServerError)] [ProducesResponseType(StatusCodes.Status303SeeOther)] [HttpPost] [Route("RegisterUsers")] public async Task<ActionResult<List<UsersInfo>>> RegisterUsers(List<UsersInfo> Users) { // .. how to detect errors here ... return Users; }当接口收到格式错误的
UsersInfo类型请求体时,该方法的逻辑代码不会执行,需捕获并记录这类自动返回的HTTP 400响应。
解决方案
方法一:自定义中间件捕获响应
请求模型绑定错误发生在进入控制器方法之前,可通过自定义中间件捕获这类400响应:
- 创建中间件类:
public class ValidationErrorLoggingMiddleware { private readonly RequestDelegate _next; private readonly ILogger<ValidationErrorLoggingMiddleware> _logger; public ValidationErrorLoggingMiddleware(RequestDelegate next, ILogger<ValidationErrorLoggingMiddleware> logger) { _next = next; _logger = logger; } public async Task InvokeAsync(HttpContext context) { await _next(context); if (context.Response.StatusCode == StatusCodes.Status400BadRequest) { context.Request.Body.Position = 0; var requestBody = await new StreamReader(context.Request.Body).ReadToEndAsync(); _logger.LogError("请求模型绑定失败,状态码400。请求路径:{Path},请求体:{RequestBody}", context.Request.Path, requestBody); } } }
- 在
Program.cs中注册中间件(注意顺序,需放在UseRouting之后、UseEndpoints之前):
var builder = WebApplication.CreateBuilder(args); builder.Services.AddControllers(); var app = builder.Build(); app.UseHttpsRedirection(); app.UseRouting(); app.UseAuthorization(); // 注册自定义日志中间件 app.UseMiddleware<ValidationErrorLoggingMiddleware>(); app.MapControllers(); app.Run();
- 启用请求重读(默认请求流仅能读取一次):
// 在Program.cs的app构建后添加 app.Use(async (context, next) => { context.Request.EnableBuffering(); await next(); });
方法二:配置API行为选项拦截验证错误
通过ConfigureApiBehaviorOptions直接拦截模型验证失败场景,获取错误详情并记录:
在Program.cs中配置:
builder.Services.AddControllers() .ConfigureApiBehaviorOptions(options => { var originalFactory = options.InvalidModelStateResponseFactory; options.InvalidModelStateResponseFactory = context => { var errors = context.ModelState .Where(x => x.Value.Errors.Any()) .ToDictionary(kv => kv.Key, kv => kv.Value.Errors.Select(e => e.ErrorMessage).ToArray()); var logger = context.HttpContext.RequestServices.GetRequiredService<ILogger<Program>>(); logger.LogError("模型验证失败,请求路径:{Path},错误详情:{Errors}", context.HttpContext.Request.Path, System.Text.Json.JsonSerializer.Serialize(errors)); return originalFactory(context); }; });
这种方式无需处理响应流,可直接拿到模型验证的具体错误信息。
方法三:使用全局结果过滤器
实现IAlwaysRunResultFilter确保过滤器在模型验证失败时仍能执行,捕获400响应:
- 创建过滤器类:
public class ValidationLoggingFilter : IAlwaysRunResultFilter { private readonly ILogger<ValidationLoggingFilter> _logger; public ValidationLoggingFilter(ILogger<ValidationLoggingFilter> logger) { _logger = logger; } public async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next) { if (context.Result is BadRequestObjectResult badRequestResult) { var errors = badRequestResult.Value as SerializableError; if (errors != null) { _logger.LogError("模型验证失败,请求路径:{Path},错误:{Errors}", context.HttpContext.Request.Path, System.Text.Json.JsonSerializer.Serialize(errors)); } } await next(); } }
- 在
Program.cs中注册全局过滤器:
builder.Services.AddControllers(options => { options.Filters.Add<ValidationLoggingFilter>(); });
内容的提问来源于stack exchange,提问作者softwareminded
相关产品推荐
相关产品推荐

