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

自定义IRouteConstraint校验失败时返回ProblemDetails响应而非默认404

原代码问题

IRouteConstraint.Match 方法要求返回布尔值,你返回ProblemDetails属于语法错误。且默认路由约束匹配失败时,ASP.NET Core会判定无匹配路由直接返回404,不会触发自定义响应逻辑,需要调整实现方式。

方案1:改造路由约束实现需求

1. 重写约束逻辑

校验失败时直接向当前HttpContext写入400响应,再返回false终止路由匹配,框架会直接返回你写入的响应内容,不会 fallback 到404:

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing;
using Microsoft.AspNetCore.Mvc;

public class CountryRouteConstraint : IRouteConstraint
{
    private readonly List<string> _countryCodes = new() { "AF", "AX", "AL", "DZ", "AS", "AD", "AO" /*...*/ };

    public bool Match(HttpContext context, IRouter route, string routeKey, RouteValueDictionary values, RouteDirection routeDirection)
    {
        // 只处理入站请求,跳过URL生成场景的校验
        if (routeDirection != RouteDirection.IncomingRequest)
            return true;

        values.TryGetValue(routeKey, out var value);
        var country = (value as string ?? string.Empty).ToUpper();
        
        if (_countryCodes.Contains(country))
            return true;

        // 直接写入400 + ProblemDetails响应
        context.Response.StatusCode = StatusCodes.Status400BadRequest;
        context.Response.WriteAsJsonAsync(new ProblemDetails
        {
            Status = StatusCodes.Status400BadRequest,
            Title = $@"无有效国家代码:""{country}""",
            Instance = context.Request.Path
        }).Wait();
        return false;
    }
}

2. 注册约束

在Program.cs中注册自定义路由约束:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRouting(options =>
{
    // 给约束起别名,后续路由模板可以直接用 :country 调用
    options.ConstraintMap.Add("country", typeof(CountryRouteConstraint));
});

// 其余服务注册...

var app = builder.Build();
// 中间件配置...
app.Run();

3. 路由中使用约束

// 最小API示例
app.MapGet("/api/countries/{country:country}", (string country) =>
{
    return Results.Ok($"请求国家代码:{country}");
});

// 控制器路由示例
[Route("api/[controller]")]
public class CountriesController : ControllerBase
{
    [HttpGet("{country:country}")]
    public IActionResult Get(string country)
    {
        return Ok(country);
    }
}

方案2:端点过滤器实现(.NET 7+ 推荐)

路由约束的Match是同步方法,WriteAsJsonAsync().Wait()存在低概率线程阻塞风险,高并发场景更推荐用异步的端点过滤器实现,不会干扰路由匹配逻辑:

1. 实现过滤器

public class CountryCodeValidationFilter : IEndpointFilter
{
    private readonly List<string> _countryCodes = new() { "AF", "AX", "AL", "DZ", "AS", "AD", "AO" /*...*/ };
    public async ValueTask<object?> InvokeAsync(EndpointFilterInvocationContext context, EndpointFilterDelegate next)
    {
        // 提取路由参数中的country值
        if (!context.HttpContext.Request.RouteValues.TryGetValue("country", out var value) 
            || value is not string country 
            || !_countryCodes.Contains(country.ToUpper()))
        {
            return Results.BadRequest(new ProblemDetails
            {
                Status = StatusCodes.Status400BadRequest,
                Title = $@"无有效国家代码:""{country}""",
                Instance = context.HttpContext.Request.Path
            });
        }
        return await next(context);
    }
}

2. 端点挂载过滤器

app.MapGet("/api/countries/{country}", (string country) =>
{
    return Results.Ok($"请求国家代码:{country}");
}).AddEndpointFilter<CountryCodeValidationFilter>();

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 15:36:03