短路与分支
使用 MapWhen、UseWhen 和终止中间件,根据请求条件对管道进行分支或终止。
短路与分支 是 CoddyKit 上的免费 C# Academy 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 C# Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 C# Academy 课程共包含 4 节课。
分支与短路
并非每个请求都应遍历完整的中间件管道。ASP.NET Core 提供了用于分支(将部分请求路由到不同管道)和短路(停止处理并立即返回)的工具。
Map:按路径永久分支
Map 会创建一个永久分支——匹配此前缀的请求会进入该分支,且绝不会返回主管道。
app.Map("/api", apiApp =>
{
apiApp.UseAuthentication();
apiApp.UseAuthorization();
apiApp.Run(async ctx =>
await ctx.Response.WriteAsync("API branch"));
});
// Requests to /api/... enter the branch above.
// Requests to /public/... skip the branch entirely.
app.Run(async ctx =>
await ctx.Response.WriteAsync("Main pipeline"));MapWhen:按谓词分支
MapWhen 可以根据任意条件进行分支(例如标头、查询参数或自定义逻辑)。与 Map 一样,该分支是永久的,不会重新加入主管道。
// Branch when a specific header is present
app.MapWhen(
ctx => ctx.Request.Headers.ContainsKey("X-Internal"),
internalApp =>
{
internalApp.UseMiddleware<InternalApiMiddleware>();
internalApp.Run(async ctx =>
await ctx.Response.WriteAsync("Internal route"));
});
// Branch on query parameter
app.MapWhen(
ctx => ctx.Request.Query.ContainsKey("legacy"),
legacyApp => legacyApp.UseMiddleware<LegacyHandlerMiddleware>());UseWhen:完成后重新加入的条件分支
UseWhen 类似于 MapWhen,但分支完成后会重新加入主管道。这样,您可以有条件地添加中间件,而无需创建独立分支。
// Log only for authenticated API calls; public routes not logged
app.UseWhen(
ctx => ctx.Request.Path.StartsWithSegments("/api")
&& ctx.User.Identity?.IsAuthenticated == true,
loggedApp =>
{
loggedApp.UseMiddleware<AuditMiddleware>();
});
// All requests continue here after the branch
app.UseRouting();
app.MapControllers();不调用下一个组件来实现短路
任何中间件都可以通过写入响应而不调用 next 来实现短路。管道会在该处停止,响应也会返回给客户端。
app.Use(async (ctx, next) =>
{
// IP allowlist check
var ip = ctx.Connection.RemoteIpAddress?.ToString();
var allowed = new[] { "127.0.0.1", "::1", "10.0.0.0/8" };
if (!IsAllowed(ip, allowed))
{
ctx.Response.StatusCode = 403;
await ctx.Response.WriteAsJsonAsync(
new { error = "Access denied from this IP" });
return; // short-circuit
}
await next(ctx); // proceed
});.NET 8 中的 ShortCircuit()
在 .NET 8 中,MapShortCircuit 和端点上的 ShortCircuit() 扩展提供了一条声明式且高度优化的短路路径。
// Reject known bad paths immediately — skip entire pipeline
app.MapShortCircuit(404, "robots.txt", "favicon.ico");
// Or on a specific endpoint:
app.MapGet("/health", () => "OK")
.ShortCircuit(); // skips auth, rate limiting, etc.
// 'Run' middleware also short-circuits:
app.Map("/old-api", old =>
old.Run(ctx =>
{
ctx.Response.StatusCode = 301;
ctx.Response.Headers.Location = "/api/v2";
return Task.CompletedTask;
}));终止中间件与端点路由
在 .NET 3 之前,app.Run() 是唯一的终止选项。现在,更推荐使用端点路由(MapGet、MapControllers),因为它可以参与授权、速率限制和元数据处理。
// OLD: terminal middleware
app.Run(async ctx => {
if (ctx.Request.Path == "/ping")
await ctx.Response.WriteAsync("pong");
});
// PREFERRED: endpoint routing
app.MapGet("/ping", () => "pong")
.WithTags("Health")
.AllowAnonymous()
.RequireRateLimiting("basic");路径匹配细节
Map("/api") 会匹配 /api 和 /api/anything。在分支内部,匹配的路径会从 Request.Path 中移除,并放入 Request.PathBase。
app.Map("/api", apiApp =>
{
apiApp.Use(async (ctx, next) =>
{
// Path in branch: /users/42 (prefix removed)
Console.WriteLine(ctx.Request.Path); // /users/42
Console.WriteLine(ctx.Request.PathBase); // /api
await next(ctx);
});
apiApp.MapGet("/users/{id}", (int id) => id);
});组合使用分支模式
实际应用会组合使用 Map、UseWhen 和短路机制来创建分层管道:公共路由保持轻量,API 路由加入身份验证,管理路由则执行额外检查。
// Public area — no auth
app.Map("/public", pub =>
{
pub.MapGet("/health", () => "OK");
pub.MapGet("/docs", () => "Documentation");
});
// API area — full auth + rate limiting
app.Map("/api", api =>
{
api.UseAuthentication();
api.UseAuthorization();
api.UseRateLimiter();
api.MapControllers();
});
// Admin area — require admin role
app.Map("/admin", admin =>
{
admin.UseAuthentication();
admin.UseAuthorization();
admin.MapControllers().RequireAuthorization("AdminPolicy");
});实际案例:A/B 测试中间件
A/B 测试中间件会根据 Cookie 或标头将请求分发给不同的处理程序,而无需修改端点代码。
app.UseWhen(
ctx => ctx.Request.Cookies.TryGetValue("ab-group", out var g) && g == "B",
betaApp =>
{
betaApp.Use(async (ctx, next) =>
{
ctx.Items["IsGroupB"] = true;
await next(ctx);
});
});
// Endpoint reads the flag:
app.MapGet("/products", (HttpContext ctx, ProductService svc) =>
{
bool isB = ctx.Items.ContainsKey("IsGroupB");
return isB ? svc.GetNewLayoutAsync() : svc.GetOldLayoutAsync();
});快速检查
MapWhen 和 UseWhen 的关键区别是什么?
回顾:短路与分支
关键要点:
Map:基于路径的永久分支(不会重新加入)MapWhen:基于谓词的永久分支UseWhen:完成后重新加入主管道的条件分支- 短路:不调用
next,写入响应并返回 ShortCircuit()(.NET 8):声明式、经过优化的终止端点- 组合使用分支来构建分层管道:公共 / API / 管理
用 AI 导师学习 C# — 免费
在浏览器中编写并运行真实代码,获得全天候 AI 导师的即时帮助,并在网页或应用中继续学习。
- 课程
- 93
- 课程
- 346
常见问题解答
「短路与分支」课时是免费的吗?
是的 — 「短路与分支」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 C# Academy 课程的其余内容,请升级到 CoddyKit PRO。 C# Academy 课程共包含 4 节课。
「短路与分支」这节课中我会学到什么?
使用 MapWhen、UseWhen 和终止中间件,根据请求条件对管道进行分支或终止。 你通过在浏览器中直接运行的动手代码来练习 C# Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 C# Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 C# Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。
「短路与分支」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 C# Academy 课中编写并运行代码吗?
能。每节 C# Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。