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

自定义异常处理器中GetEndpoint为Null且RouteValues为空的问题排查

问题原因

你当前使用的UseExceptionHandler默认会在捕获异常后创建一个新的HttpContext生成错误响应,这个新上下文不包含原请求的Endpoint和RouteValues信息,因此你获取到的是空值。此外,你没有使用存储原请求路由信息的IExceptionHandlerPathFeature接口,导致无法拿到原请求的路由数据。

解决方案

方案一:改用自定义异常中间件(推荐)

直接编写包含try/catch的自定义中间件,在原请求上下文上处理异常,可直接访问原请求的Endpoint和RouteValues:

public static IApplicationBuilder UseCustomExceptionHandler(this IApplicationBuilder app)
{
    return app.Use(async (context, next) =>
    {
        try
        {
            await next();
            // 处理404状态码(可选)
            if (context.Response.StatusCode == StatusCodes.Status404NotFound && !context.Response.HasStarted)
            {
                var problemDetails = new ProblemDetails
                {
                    Status = StatusCodes.Status404NotFound,
                    Title = "资源未找到",
                    Detail = $"请求路径 {context.Request.Path} 不存在",
                    Instance = context.Request.Path
                };
                
                AppendRouteAndEndpointInfo(context, problemDetails);
                
                context.Response.ContentType = "application/problem+json";
                await context.Response.WriteAsJsonAsync(problemDetails);
            }
        }
        catch (Exception ex)
        {
            var problemDetails = new ProblemDetails
            {
                Status = StatusCodes.Status500InternalServerError,
                Title = "发生未处理异常",
                Detail = ex.Message,
                Instance = context.Request.Path
            };
            
            AppendRouteAndEndpointInfo(context, problemDetails);
            
            if (!context.Response.HasStarted)
            {
                context.Response.Clear();
                context.Response.StatusCode = problemDetails.Status.Value;
                context.Response.ContentType = "application/problem+json";
                await context.Response.WriteAsJsonAsync(problemDetails);
            }
        }
    });
    
    void AppendRouteAndEndpointInfo(HttpContext ctx, ProblemDetails details)
    {
        var endpoint = ctx.GetEndpoint();
        var routeValues = ctx.Features.Get<IRouteValuesFeature>()?.RouteValues;
        
        if (routeValues != null && routeValues.Any())
        {
            details.Extensions["RouteValues"] = routeValues;
        }
        if (endpoint != null)
        {
            details.Extensions["Endpoint"] = endpoint.DisplayName;
        }
    }
}

调整管道注册顺序,将该中间件放在Cors之后、其他业务中间件之前:

var app = builder.Build();
app.UseCors("OurPolicy");

// 注册自定义异常中间件
app.UseCustomExceptionHandler();

app.UseStatusCodePages();
app.UseAuthentication();
app.UseAuthorization();

app.AddPeopleEndpoints();

await app.RunAsync();

方案二:基于UseExceptionHandler改造(兼容原有逻辑)

如果坚持使用UseExceptionHandler,可通过IExceptionHandlerPathFeature获取原请求路由值,并通过上下文Items存储原Endpoint:

  1. 添加中间件存储原请求的Endpoint:
public static IApplicationBuilder UseStoreOriginalEndpoint(this IApplicationBuilder app)
{
    return app.Use(async (context, next) =>
    {
        await next();
        var endpoint = context.GetEndpoint();
        if (endpoint != null)
        {
            context.Items["OriginalEndpoint"] = endpoint;
        }
    });
}
  1. 修改异常处理器逻辑:
public static IApplicationBuilder UseExceptionHandlerMiddleware(this IApplicationBuilder app)
    => app.UseExceptionHandler(new ExceptionHandlerOptions
    {
        AllowStatusCode404Response = true,
        ExceptionHandler = async context =>
        {
            var exceptionPathFeature = context.Features.Get<IExceptionHandlerPathFeature>();
            var exception = exceptionPathFeature?.Error;
            
            // 获取原请求路由值
            var routeValues = exceptionPathFeature?.RouteValues;
            // 获取原请求Endpoint
            var originalContext = context.Features.Get<IExceptionHandlerFeature>()?.Context;
            var endpoint = originalContext?.Items["OriginalEndpoint"] as Endpoint;

            var problemDetails = new ProblemDetails
            {
                Status = StatusCodes.Status500InternalServerError,
                Title = "发生未处理异常",
                Detail = exception?.Message,
                Instance = exceptionPathFeature?.Path
            };
            
            if (routeValues != null && routeValues.Any())
            {
                problemDetails.Extensions["RouteValues"] = routeValues;
            }
            if (endpoint != null)
            {
                problemDetails.Extensions["Endpoint"] = endpoint.DisplayName;
            }
            
            context.Response.StatusCode = problemDetails.Status.Value;
            context.Response.ContentType = "application/problem+json";
            await context.Response.WriteAsJsonAsync(problemDetails);
        }
    });
  1. 调整管道顺序:
var app = builder.Build();
app.UseCors("OurPolicy");

app.UseExceptionHandlerMiddleware();
app.UseStatusCodePages();

app.UseAuthentication();
app.UseAuthorization();

// 注册存储原Endpoint的中间件
app.UseStoreOriginalEndpoint();

app.AddPeopleEndpoints();

await app.RunAsync();

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 03:34:57