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

.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响应:

  1. 创建中间件类:
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);
        }
    }
}
  1. 在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();
  1. 启用请求重读(默认请求流仅能读取一次):
// 在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响应:

  1. 创建过滤器类:
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();
    }
}
  1. 在Program.cs中注册全局过滤器:
builder.Services.AddControllers(options =>
{
    options.Filters.Add<ValidationLoggingFilter>();
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 21:15:35