ASP.NET Core Web API中间件修改Request.Path未切换控制器/动作
你的问题出在中间件顺序错误,以及ASP.NET Core路由系统的执行时机限制导致的。
核心原因
ASP.NET Core的路由匹配(由EndpointRoutingMiddleware处理)需要在授权中间件(UseAuthorization)之前执行,但你的代码没有显式调用UseRouting,导致MapControllers隐式添加的EndpointRoutingMiddleware被放在了UseAuthorization之后。虽然你修改了Request.Path,但错误的执行顺序让路由匹配逻辑无法正确识别修改后的路径,最终还是沿用了原始路径的匹配结果。
同时,这种顺序也违反了ASP.NET Core官方推荐的中间件执行顺序,会引发授权逻辑无法正确获取端点权限配置等潜在问题。
解决方案
方案1:调整中间件顺序(推荐)
显式添加UseRouting,将自定义中间件放在UseRouting之前(确保路径修改在路由匹配前完成),同时将UseAuthorization放在UseRouting之后,符合官方规范:
using Sandbox.Middleware; var builder = WebApplication.CreateBuilder(args); builder.Services.AddControllers(); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); var app = builder.Build(); if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } // 自定义中间件放在UseRouting之前,保证路径修改先于路由匹配 app.UseMiddleware<ModifyControllerMiddleware>(); app.UseHttpsRedirection(); // 显式声明路由中间件,确保路由匹配在授权之前执行 app.UseRouting(); app.UseAuthorization(); app.MapControllers(); app.Run();
方案2:使用自定义路由策略(更灵活)
如果不想调整中间件顺序,可以通过实现IEndpointSelectorPolicy直接在路由匹配阶段根据请求头选择目标端点,无需修改Request.Path:
- 创建自定义路由策略类:
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; using Microsoft.AspNetCore.Routing.Matching; using Microsoft.AspNetCore.Mvc.Controllers; namespace Sandbox.Middleware { public class HeaderBasedEndpointSelectorPolicy : IEndpointSelectorPolicy { public bool AppliesToEndpoints(IReadOnlyList<Endpoint> endpoints) => true; public Task ApplyAsync(HttpContext httpContext, CandidateSet candidates) { if (!httpContext.Request.Headers.TryGetValue("x-intercept", out var interceptValue)) return Task.CompletedTask; var targetAction = interceptValue switch { "1" => "Heartbeat", "2" => "Deadbeat", _ => null }; if (targetAction == null) return Task.CompletedTask; // 遍历候选端点,筛选出目标动作对应的端点 for (int i = 0; i < candidates.Count; i++) { if (candidates[i].Endpoint.Metadata.GetMetadata<ControllerActionDescriptor>()?.ActionName == targetAction) { // 标记该端点为有效,其余为无效 candidates.SetValidity(i, true); for (int j = 0; j < candidates.Count; j++) { if (j != i) candidates.SetValidity(j, false); } break; } } return Task.CompletedTask; } } }
- 在Program.cs中注册该策略:
builder.Services.AddSingleton<IEndpointSelectorPolicy, HeaderBasedEndpointSelectorPolicy>();
这种方式直接在路由匹配阶段干预端点选择,更贴合ASP.NET Core的路由设计逻辑,也避免了修改请求路径可能带来的其他副作用。
验证
调整中间件顺序或添加自定义路由策略后,发送带有x-intercept:2的请求到/Diagnostics/Heartbeat,应该会正确路由到Deadbeat动作。
内容的提问来源于stack exchange,提问作者Gabriel Read

