You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

ASP.NET Core 5控制器中如何拦截POST请求中的无效JSON参数

检测ASP.NET Core 5 API中的未知POST参数并返回400错误

针对你的需求,有两种比较优雅的方案,比你之前尝试的ActionFilter或用object接收的方式更贴合ASP.NET Core的设计思路:

方案一:利用System.Text.Json内置配置+全局异常过滤器

ASP.NET Core 5默认用System.Text.Json做序列化,它的默认行为是忽略请求中的未知字段,不会抛出异常。我们可以修改这个规则,让它遇到未定义字段时抛出异常,再通过全局异常过滤器捕获并返回400错误。

步骤1:修改Json序列化配置

Startup.csConfigureServices方法里,配置控制器的Json选项:

services.AddControllers()
    .AddJsonOptions(options =>
    {
        // 关闭"忽略未知字段",遇到未定义属性时抛出JsonException
        options.JsonSerializerOptions.IgnoreUnknownFields = false;
    });

步骤2:创建全局异常过滤器

写一个过滤器专门捕获JsonException,把它转换成标准的400错误响应:

public class JsonUnknownFieldExceptionFilter : IExceptionFilter
{
    private readonly ILogger<JsonUnknownFieldExceptionFilter> _logger;

    public JsonUnknownFieldExceptionFilter(ILogger<JsonUnknownFieldExceptionFilter> logger)
    {
        _logger = logger;
    }

    public void OnException(ExceptionContext context)
    {
        if (context.Exception is JsonException jsonEx)
        {
            _logger.LogError(jsonEx, "请求包含未定义的参数");
            
            context.Result = new BadRequestObjectResult(new
            {
                StatusCode = StatusCodes.Status400BadRequest,
                Message = "请求包含无效参数",
                Detail = jsonEx.Message
            });
            context.ExceptionHandled = true;
        }
    }
}

步骤3:注册全局过滤器

同样在Startup.csConfigureServices中,把过滤器添加到控制器配置里:

services.AddControllers(options =>
{
    options.Filters.Add<JsonUnknownFieldExceptionFilter>();
})
.AddJsonOptions(options =>
{
    options.JsonSerializerOptions.IgnoreUnknownFields = false;
});

这样一来,只要请求里有未定义的参数,System.Text.Json会直接抛出异常,过滤器捕获后立刻返回400错误,请求根本不会到达你的控制器方法,完全符合你的需求。

方案二:使用Json Schema验证(精细化控制方案)

如果需要针对不同接口做差异化处理(比如部分接口允许未知字段,部分不允许),可以用Json Schema做请求体验证。这种方式需要引入System.Text.Json.Schema NuGet包(如果用Newtonsoft.Json替代默认序列化,也可以用它对应的Schema包)。

示例代码(System.Text.Json.Schema版本)

  1. 先安装NuGet包:System.Text.Json.Schema
  2. 创建一个ActionFilter实现验证逻辑:
public class ValidateRequestSchemaAttribute : ActionFilterAttribute
{
    private readonly JsonSchema _schema;

    public ValidateRequestSchemaAttribute(Type requestType)
    {
        // 从请求模型类型自动生成Json Schema
        _schema = JsonSchemaGenerator.Generate(requestType);
    }

    public override async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
    {
        var request = context.HttpContext.Request;
        request.Body.Position = 0; // 重置请求体读取位置,确保能完整读取
        var requestBody = await new StreamReader(request.Body).ReadToEndAsync();

        var validationResult = JsonSchemaValidator.Validate(requestBody, _schema);
        if (!validationResult.IsValid)
        {
            context.Result = new BadRequestObjectResult(new
            {
                StatusCode = StatusCodes.Status400BadRequest,
                Message = "请求参数不符合要求",
                Errors = validationResult.Errors.Select(e => e.Message)
            });
            return;
        }

        await next();
    }
}
  1. 在需要验证的控制器方法上标记这个特性:
[HttpPost]
[ValidateRequestSchema(typeof(MyRequestType))]
public async Task<MyResponseType> Post([FromBody] MyRequestType request)
{
    // 业务处理代码...
}

这种方案的优势是灵活性高,可以针对单个接口配置验证规则,但代码量会比方案一多一些。

为什么不推荐你之前的尝试?

  • ActionFilter手动解析请求体:需要重复读取请求体(默认请求体只能读一次,还要手动重置位置),不仅繁琐,还可能影响性能。
  • object接收请求:需要手动反射检查属性,代码不够优雅,也没法利用ASP.NET Core自带的模型绑定和验证机制。

上面两种方案都能很好解决你的问题,方案一更简洁适合全局统一规则,方案二更灵活适合精细化场景,你可以根据自己的需求选择。

内容的提问来源于stack exchange,提问作者the-robot

火山引擎 最新活动