中间件短路需显式调用 return 并写入响应,否则请求挂起;漏掉 await next(context) 会导致后续中间件(含路由、授权)全跳过;use 与 usemiddleware 短路行为一致但生命周期不同;map/mapwhen 是分叉非短路。

中间件短路不是“加个 return 就完事”,它直接决定请求是否继续走管道;漏掉 await next(context) 或错放位置,后续所有中间件(包括路由、MVC、授权)全被跳过。
短路必须显式控制,不能靠“没写 next 就自动短路”
很多人以为只要不调用 next,中间件就自然短路——这是错觉。ASP.NET Core 的管道不会帮你兜底,它只按你写的逻辑执行:写了 await next(context) 才往下走,不写就停在当前中间件,但你得自己负责写出完整响应(否则客户端收不到任何东西,连接挂起)。
- 短路前必须设置
context.Response.StatusCode和至少一个响应体(如WriteAsync),否则浏览器会一直等待 - 常见错误是只写
return;却忘了写响应,结果前端卡在 pending 状态 - 短路后建议调用
context.Response.HasStarted判断是否已发送头,避免重复写入报错
Use vs UseMiddleware<t></t>:短路行为一致,但生命周期不同
两种注册方式都能实现短路,区别不在“能不能短路”,而在服务注入和实例复用上:
-
Use注册的是内联委托,每次请求都新建闭包,无法直接注入 scoped 服务(如ILogger<t></t>、IDbContext) -
UseMiddleware<t></t>通过 DI 构造中间件实例,支持构造函数注入,且InvokeAsync中可安全获取 scoped 服务 - 无论哪种,短路逻辑都一样:不 await
next(context)+ 自行写响应 = 短路
短路常用于这几种真实场景,别硬套模板
短路不是炫技,而是为明确拦截条件提前终结请求。典型用法有:
- 静态资源命中时直接返回(如
/favicon.ico或public/下文件),不进 MVC 管道 - JWT 解析失败或过期,直接返回
401,不走后续UseAuthorization() - 请求路径匹配预设白名单(如健康检查
/health),绕过认证和日志中间件 - 请求头缺失必要字段(如
X-Api-Key),立即返回400,不进业务逻辑
分支管道(Map/MapWhen)不是短路,别混用
Map 和 MapWhen 是把管道“分叉”,不是中断主链。它们创建子管道,主链依然继续执行(除非你在子管道里短路)。比如:
app.UseMapWhen(ctx => ctx.Request.Path.StartsWithSegments("/admin"), adminApp =>
{
adminApp.UseAuthentication();
adminApp.UseAuthorization();
adminApp.UseEndpoints(...);
});
这段代码中,非 /admin 路径的请求仍会走主管道剩余中间件;而 /admin 请求进入子管道后,若在其中短路(比如未登录返回 401),只影响该子管道,不影响主链其他中间件。
真正容易被忽略的是:短路必须发生在「你控制的那个中间件内」,而不是依赖框架自动判断;一旦漏掉 await next(context) 又没写响应,整个请求就静默卡死——这种问题在线上很难复现,但压测时极易暴露。










