理解 .NET 中的中间件(Middleware):请求管道的核心机制
在 ASP.NET Core 中,中间件(Middleware)是整个 Web 应用的核心机制之一。所有 HTTP 请求都会依次通过一系列中间件处理,这些中间件共同组成了所谓的 请求管道(Request Pipeline) 。理解中间件不仅有助于掌握 ASP.NET Core 的工作原理,更能帮助你构建结构清晰、可扩展且易维护的 Web 应用。
本文将从中间件的概念、执行流程、如何编写自定义中间件以及开发中的最佳实践等方面进行介绍。
一、中间件是什么?
中间件是用于处理 HTTP 请求和响应的组件。每个中间件在管道中有两个职责:
- 处理当前请求
- 将请求传递给管道中的下一个中间件(可选)
典型逻辑可以概括为:
css
Request → [Middleware1] → [Middleware2] → ... → Endpoint
中间件既可以选择"继续往下传",也可以"短路"整个请求。
例如:
- 认证中间件可能会拒绝未授权请求,直接返回 401。
- 静态文件中间件会直接返回文件内容,不继续传递到 MVC 层。
二、中间件的注册方式
在 .NET 6+ 的程序入口里,你常看到这样的代码:
ini
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();
UseXXX() 即是在管道中注册中间件。
通常中间件的处理顺序非常重要,例如:
UseRouting()必须在UseEndpoints()前。UseAuthorization()要在UseAuthentication()后。
如果顺序错误,可能导致路由不生效或认证失败。
三、编写一个自定义中间件
自定义中间件通常有两种方式:类方式与委托方式。
方式一:通过类编写中间件
1. 编写中间件类
csharp
public class RequestLogMiddleware
{
private readonly RequestDelegate _next;
public RequestLogMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
Console.WriteLine($"[Request] {context.Request.Method} {context.Request.Path}");
await _next(context); // 继续传递给下一个中间件
Console.WriteLine($"[Response] {context.Response.StatusCode}");
}
}
2. 注册中间件
ini
app.UseMiddleware<RequestLogMiddleware>();
方式二:使用 inline delegate 简写(更轻量)
python
app.Use(async (context, next) =>
{
Console.WriteLine("Before");
await next(context);
Console.WriteLine("After");
});
四、中间件执行流程示例
假设我们有三层中间件:
python
app.Use(async (context, next) =>
{
Console.WriteLine("1 - Before");
await next();
Console.WriteLine("1 - After");
});
app.Use(async (context, next) =>
{
Console.WriteLine("2 - Before");
await next();
Console.WriteLine("2 - After");
});
app.Map("/hello", () => "Hello");
执行顺序会是:
1 - Before
2 - Before
(进入 endpoint)
2 - After
1 - After
这体现了 洋葱模型(Onion Model) 的特性。
五、中间件的典型应用场景
中间件的应用非常广泛,几乎所有现代 Web 框架都会使用类似的机制。ASP.NET Core 中常见的中间件包括:
- 异常捕获(UseExceptionHandler)
- 静态文件处理(UseStaticFiles)
- 跨域 CORS(UseCors)
- 身份认证 Auth(UseAuthentication)
- 压缩响应(UseResponseCompression)
- 日志记录与监控(自定义)
例如:要捕获全局异常,可以这样:
arduino
app.UseExceptionHandler("/error");
或者写一个自定义全局异常中间件。
六、开发中常见问题与最佳实践
1. 中间件顺序非常关键
- 错误顺序会导致功能失效
- 官方文档明确列出了推荐顺序,建议参考
2. 避免在中间件中做耗时操作
慢中间件会拖垮整个链路。
3. 如果中止管道,要确保正确设置响应(StatusCode、Header)
例如,权限不足时返回:
ini
context.Response.StatusCode = StatusCodes.Status403Forbidden;
return;
4. 避免在中间件中直接访问大量业务逻辑
业务逻辑应该在 Service 层。
结语
中间件是 ASP.NET Core 请求处理的基础结构,掌握中间件可以帮助你:
- 更好地理解框架内部机制
- 编写可维护的横切逻辑(监控、日志、权限等)
- 构建复杂的请求管理系统