ASP.NET Core的中间件是组成请求处理管道的核心单元,每个中间件都可以对进入应用的HTTP请求和离开应用的HTTP响应进行处理,多个中间件按照添加顺序串联起来,就形成了完整的请求处理流程。
中间件的核心作用
中间件在ASP.NET Core中主要承担以下几类职责:
- 请求预处理:比如验证请求头信息、解析身份认证令牌、记录请求日志等,在请求到达业务控制器前完成前置校验。
- 请求转发:将符合条件的请求传递给下一个中间件,或者直接将请求短路返回响应,不再执行后续逻辑。
- 响应处理:对业务处理完成后返回的响应内容进行修改,比如添加统一的响应头、处理跨域配置、捕获全局异常等。
- 管道构建:通过多个功能不同的中间件组合,形成覆盖认证、缓存、路由、业务处理等全环节的请求处理管道。
中间件的运行原理
每个中间件本质是一个委托,接收HttpContext对象和下一个中间件的引用作为参数。当请求进入管道时,会按照中间件添加的顺序依次执行,每个中间件可以选择调用下一个中间件,也可以直接返回响应终止流程。
中间件的执行流程可以用以下逻辑表示:
// 中间件委托的基本形式
public delegate Task RequestDelegate(HttpContext context);
// 单个中间件的简化逻辑
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
{
// 请求进入当前中间件时的处理逻辑
// 比如记录请求开始时间
var startTime = DateTime.Now;
// 调用下一个中间件,将请求传递下去
await next(context);
// 响应返回当前中间件时的处理逻辑
// 比如记录请求耗时
var elapsed = DateTime.Now - startTime;
Console.WriteLine($"请求耗时:{elapsed.TotalMilliseconds}ms");
}
自定义中间件的方式
ASP.NET Core支持两种自定义中间件的方式,分别是基于约定的中间件类和内联中间件委托。
1. 基于约定的中间件类
这种方式适合逻辑复杂、可复用性高的中间件,需要定义包含InvokeAsync方法的类,构造函数可以注入依赖的服务。
// 自定义日志中间件
public class RequestLogMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger<RequestLogMiddleware> _logger;
// 构造函数注入下一个中间件和日志服务
public RequestLogMiddleware(RequestDelegate next, ILogger<RequestLogMiddleware> logger)
{
_next = next;
_logger = logger;
}
// 必须定义InvokeAsync方法,参数是HttpContext
public async Task InvokeAsync(HttpContext context)
{
// 请求处理前记录信息
_logger.LogInformation($"收到请求:{context.Request.Method} {context.Request.Path}");
// 传递请求到下一个中间件
await _next(context);
// 响应处理后记录信息
_logger.LogInformation($"返回响应状态码:{context.Response.StatusCode}");
}
}
// 扩展方法方便注册中间件
public static class RequestLogMiddlewareExtensions
{
public static IApplicationBuilder UseRequestLog(this IApplicationBuilder builder)
{
return builder.UseMiddleware<RequestLogMiddleware>();
}
}
2. 内联中间件委托
这种方式适合逻辑简单、仅在特定场景使用的中间件,直接在Startup.cs的Configure方法中通过Use方法添加。
// 在Configure方法中添加内联中间件
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
// 内联中间件,处理所有请求,添加自定义响应头
app.Use(async (context, next) =>
{
// 请求处理前添加响应头
context.Response.Headers.Add("X-Custom-Header", "Middleware-Demo");
// 调用下一个中间件
await next();
// 响应返回后可以添加额外逻辑
// 比如如果响应状态是404,记录未找到路径
if (context.Response.StatusCode == 404)
{
Console.WriteLine($"路径未找到:{context.Request.Path}");
}
});
}
构建请求处理管道
请求处理管道的构建是通过在Configure方法中按序添加中间件完成的,中间件的添加顺序决定了请求的处理顺序,常见的基础管道顺序如下:
| 添加顺序 | 中间件作用 | 说明 |
|---|---|---|
| 1 | 异常处理中间件 | 捕获后续中间件抛出的异常,返回统一错误响应,一般放在最前面保证能捕获所有异常 |
| 2 | HTTPS重定向中间件 | 将HTTP请求重定向到HTTPS,保证请求安全性 |
| 3 | 静态文件中间件 | 处理静态资源请求(如js、css、图片),如果请求是静态资源直接返回,不再走后续逻辑 |
| 4 | 路由中间件 | 匹配请求路径到对应的控制器和Action,确定请求的业务处理端点 |
| 5 | 认证授权中间件 | 验证用户身份和权限,不符合要求的请求直接返回401或403 |
| 6 | 业务中间件 | 自定义的业务相关中间件,比如请求日志、接口限流等 |
| 7 | 端点中间件 | 执行匹配到的控制器Action逻辑,返回业务响应 |
以下是一个完整的管道构建示例:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
// 1. 异常处理中间件,放在最前面
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
// 2. HTTPS重定向
app.UseHttpsRedirection();
// 3. 静态文件处理
app.UseStaticFiles();
// 4. 路由
app.UseRouting();
// 5. 认证授权
app.UseAuthentication();
app.UseAuthorization();
// 6. 自定义请求日志中间件
app.UseRequestLog();
// 7. 端点,匹配到业务处理
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
中间件使用注意事项
- 中间件的添加顺序非常重要,比如异常处理中间件必须放在最前面,否则无法捕获后续中间件的异常;认证中间件必须放在路由中间件之后、端点中间件之前,才能正确校验请求权限。
- 如果中间件不调用
next委托,请求会被短路,后续的所有中间件都不会执行,比如认证失败直接返回响应的场景就可以使用短路逻辑。 - 中间件的
InvokeAsync方法中的逻辑尽量不要有长时间阻塞的操作,避免影响请求处理性能,耗时操作可以考虑异步处理或者放到后台任务中。 - 依赖注入的服务在中间件中通过构造函数注入时,需要注意服务的生命周期,比如单例的中间件不能注入作用域级别的服务,否则会报生命周期不匹配的错误。
合理设计中间件的组合方式,可以让ASP.NET Core应用的请求处理流程更清晰、更易维护,同时也能将通用逻辑抽到中间件中,减少业务代码的重复。
ASP.NET_Core中间件Middleware请求处理管道C#修改时间:2026-06-22 08:19:10