当前位置: 首页 > news >正文

Asp.Net Core 请求管道中间件之Middleware

前言

中间件(Middleware)

概念

中间件是 ASP.NET Core 请求处理管道(pipeline) 中的一段可插拔组件,接收 HttpContext、执行任意逻辑、并决定是否把请求交给管道中的下一个中间件。管道呈“洋葱模型”(请求顺序进入,响应倒序返回)。

调用签名核心是:RequestDelegate next -> Task Invoke(HttpContext context)

中间件就是请求管道里的“拦路插件”,每个请求经过它,它可以拦截、修改、放行或终止请求。

1.执行流程

  • 注册顺序决定请求进入的顺序。

  • 每个中间件要决定是否 await next(context)(放行)或不调用 next(短路/终止)。

  • 请求走入时是顺序;响应返回时是逆序(栈式回退)。

  • 每个中间件既可以在请求前处理逻辑,也可以在请求后处理逻辑。

请求 -> Middleware1 -> Middleware2 -> Middleware3 -> Endpoint
响应 <- Middleware3 <- Middleware2 <- Middleware1

image-20251115220546746

2.实现方式

RequestDelegate 是中间件的核心,它接收一个 HttpContext,返回一个 Task

中间件管道本质上是 RequestDelegate 链

每个中间件通过调用 await next(context) 来传递请求。

public delegate Task RequestDelegate(HttpContext context);

2.1内联委托方式(Lambda/RequestDelegate)

直接在 Configure 中写 Lambda 表达式,RequestDelegate 链的最轻量写法。

特点

  • 快速、轻量
  • 不可复用
  • 适合简单逻辑、调试或快速原型
app.Use(async (context, next) =>
{Console.WriteLine("请求前逻辑");await next(); // 调用下一个中间件Console.WriteLine("响应后逻辑");
});

示例

Program中通过委托建立中间件

image-20251116170908801

请求http://localhost:5004/WeatherForecast接口,可以看到中间件执行逻辑

请求前逻辑
执行请求中...
响应后逻辑

image-20251116171127156

2.2类中间件方式(RequestDelegate+Invoke/InvokeAsync)

自定义中间件类,通过构造函数注入 RequestDelegate next,实现 InvokeAsync(HttpContext) 方法。

特点

  • 灵活、可复用
  • 支持依赖注入(构造函数注入服务)
  • 最常用的自定义中间件实现方式
public class CustomMiddleware
{private readonly RequestDelegate _next;public CustomMiddleware(RequestDelegate next){_next = next;}public async Task InvokeAsync(HttpContext context){Console.WriteLine("CustomMiddleware请求前逻辑");await _next(context); // 调用下一个中间件Console.WriteLine("CustomMiddleware响应后逻辑");}
}

调用方式app.UseMiddleware<MyMiddleware>();

示例

自定义中间件CustomMiddleware

image-20251116171644164

请求接口,可以看到CustomMiddleware请求逻辑

委托中间件请求前逻辑
CustomMiddleware请求前逻辑
执行请求中...
CustomMiddleware响应后逻辑
委托中间件响应后逻辑

image-20251116171730880

2.3接口(IMiddleware)

IMiddleware 是 ASP.NET Core 自带的接口化中间件实现方式,通过 DI 容器管理生命周期和依赖,简化传统中间件类的实现

特点

  • 生命周期由 DI 管理(Transient/Scoped/Singleton)
  • 不需要手动保存 _next
  • 支持复杂依赖注入,适合大型中间件
public interface IMiddleware
{Task InvokeAsync(HttpContext context, RequestDelegate next);
}public class MyMiddlewareWithDI : IMiddleware
{private readonly ILogger<MyMiddlewareWithDI> _logger;public MyMiddlewareWithDI(ILogger<MyMiddlewareWithDI> logger){_logger = logger;}public async Task InvokeAsync(HttpContext context, RequestDelegate next){_logger.LogInformation("请求前逻辑");await next(context); // 调用下一个中间件_logger.LogInformation("响应后逻辑");}
}

调用方式

// 先注入DI
services.AddTransient<MyMiddlewareWithDI>();
// 再注册中间件
app.UseMiddleware<MyMiddlewareWithDI>();

示例

新增CustomDIMiddleware实现IMiddleware

image-20251116201322994

然后先通过AddTransient<CustomDIMiddleware>()注册到DI,后面再使用UseMiddleware注册中间件CustomDIMiddleware

委托中间件请求前逻辑
CustomMiddleware请求前逻辑
CustomDIMiddleware请求前逻辑
执行请求中...
CustomDIMiddleware响应后逻辑
CustomMiddleware响应后逻辑
委托中间件响应后逻辑

image-20251116172423843

2.4RequestDelegate 工厂方式(高级方式)

将中间件逻辑封装成返回 RequestDelegate 的方法。动态生成中间件、框架内部使用。

特点

  • 高度灵活、可复用
  • 可动态生成中间件
  • 底层原理仍然是 RequestDelegate 链
public static class CustomMiddlewareFactory
{public static RequestDelegate CreateMiddleware(RequestDelegate next){return async context =>{Console.WriteLine("CustomMiddlewareFactory请求前逻辑");await next(context);Console.WriteLine("CustomMiddlewareFactory响应后逻辑");};}
}

调用方式

app.Use(CustomMiddlewareFactory.CreateMiddleware);

示例

新建自定义中间件工厂(CustomMiddlewareFactory),然后提供一个创建RequestDelegate的方法

image-20251116202241418

然后使用Use方法调用,Use方法接收一个参数是RequestDelegate并且返回RequestDelegate的委托,其实和委托方式调用蕾西,这里只是封装起来了

委托中间件请求前逻辑
CustomMiddleware请求前逻辑
CustomDIMiddleware请求前逻辑
CustomMiddlewareFactory请求前逻辑
执行请求中...
CustomMiddlewareFactory响应后逻辑
CustomDIMiddleware响应后逻辑
CustomMiddleware响应后逻辑
委托中间件响应后逻辑

image-20251116202322077

2.5内置扩展方法中间件(Use系列)

框架自带中间件封装,例如:

// 路由
app.UseRouting();
// 认证
app.UseAuthentication();
// 授权
app.UseAuthorization();
// 执行路由匹配后的请求处理
app.UseEndpoints(endpoints => { ... });

特点

  • 封装 RequestDelegate 或类中间件
  • 使用方便,集成 MVC / Minimal API
  • 灵活性略低

2.5总结

关于中间件的执行流程,这里调试一遍就很明显了:

中间件按注册顺序依次执行“请求前逻辑”,到达终点后再按相反顺序依次执行“响应后逻辑”,形成典型的洋葱模型(先进后出、后进先出)。

委托中间件请求前逻辑
CustomMiddleware请求前逻辑
CustomDIMiddleware请求前逻辑
CustomMiddlewareFactory请求前逻辑
执行请求中...
CustomMiddlewareFactory响应后逻辑
CustomDIMiddleware响应后逻辑
CustomMiddleware响应后逻辑
委托中间件响应后逻辑

总结

  • ASP.NET Core 中间件都是 RequestDelegate 链

  • _next 指向下一个中间件,形成管道链

  • 每个中间件可以在请求前/响应后处理逻辑

  • 不同实现方式只是 封装形式、复用性、DI 生命周期管理 不同

实现方式 核心机制 调用方式 特点
内联委托 / Lambda RequestDelegate app.Use(...) 快速、轻量,不可复用
类中间件 + Invoke 类 + RequestDelegate app.UseMiddleware<T>() 灵活、可复用,支持依赖注入
实现 IMiddleware 接口 IMiddleware.InvokeAsync app.UseMiddleware<T>() + DI 生命周期可控,支持复杂依赖
RequestDelegate 工厂 返回 RequestDelegate app.Use(...) 高度灵活,可动态生成
内置扩展方法 框架封装 RequestDelegate app.UseXxx() 使用方便,集成 MVC / Minimal API

3.UseRunMapUseWhen

  • Use:标准,多数中间件用 await next() 放行。

  • Run终端中间件,不接 next,写完后不会再调用后续中间件(短路)。

  • Map / MapWhen:基于路径或条件分支路由,创建子管道(可用于多态处理)。

  • UseWhen:条件中间件,满足条件时在子管道内执行 next,不满足则略过。

方法 是否可放行 作用范围 匹配条件 常见用途
Use 可放行/短路 全局管道 日志、认证、异常处理、请求处理
Run 不放行 全局管道/终端 健康检查、默认响应、短路请求
Map 可放行/短路 子管道 基于路径 分模块处理不同 URL 分支
UseWhen 可放行/短路 子管道 任意条件 条件化中间件,如仅对 API 或特定 header 生效

4.应用场景

  • 全局异常捕获(UseExceptionHandlerDeveloperExceptionPage

  • 日志/请求追踪/CorrelationId(Inject TraceId)

  • 身份认证与授权(JWT、Cookies)

  • CORS、RateLimiting、RequestSizeLimit

  • Static Files、Response Compression、Response Caching

  • HTTPS 强制、HSTS、Content-Security-Policy header 插入

  • Body 读取、请求重写(Rewrite)、路径重写(UsePathBase、RewriteOptions)

  • 流量劫持(Proxy headers)、IP 限制

5.总结

中间件是 ASP.NET Core 请求管道的插件

顺序和调用 next() 决定请求响应流程

Use 可放行,Run 终止,Map/UseWhen 创建子管道

常用于日志、异常、认证、CORS、限流、压缩等横切关注点

6.eshop的中间件

eshop中没有单独封装中间件,而是使用了MediatR命令管道统一处理业务命令的日志、参数验证、管道。

中间件是AspNetCore中很重要的组成,eshop中没有封装使用,但我还是再次学习了一遍

image-20251115232940864

📌 创作不易,感谢支持!

每一篇内容都凝聚了心血与热情,如果我的内容对您有帮助,欢迎请我喝杯咖啡☕,您的支持是我持续分享的最大动力!

💬 加入交流群(QQ群):576434538

微信打赏

http://www.jsqmd.com/news/60064/

相关文章:

  • Git推送从失败到成功的解决方案
  • Microsoft-Store-error
  • STM32 HAL库 硬件IIC 从机一些问题整理(转载)
  • 本地人推荐的火锅,天台火锅/麻辣火锅/老火锅/市井火锅/川渝火锅约会地点推荐榜单
  • OBDSTAR P003+ Kit for DC706 Tablets: Simplify ECU, EEPROM, Flash IMMO Data Diagnostics Programming
  • 全程复盘:一次枚举值永远 Cloud2的坑——从玄学随机到只读属性
  • M726芯片
  • Fast Easy Electric Oil Siphon Pump: Professional Fluid Transfer for Cars, Motorcycles Boats
  • AutoCloseable接口 try-with-resources 、 try-catch-finally
  • 第44天(中等题 数据结构)
  • rizhi
  • element-plus el-select
  • centos6.9编译安装python37——SSL 模块缺失、GCOV 链接错误,以及 Bash 命令缓存混乱
  • 在 Windows 上本地部署 ComfyUI + zImage Turbo 模型(低显存友好)
  • sg.取消按钮焦点框
  • 代码随想录Day27_贪心1
  • Day10-20251203
  • 面向人机文明的价值协同:理论、实践与评估的完整框架
  • 251203 完成比完美重要
  • python调用大模型api来进行对话
  • 主流玩家的高端主板!七彩虹战斧B850M超级黑刃主板评测:供电散热配置豪华 性价比极佳
  • 6.4 基于线弹性断裂力学(LEFM)的断裂参数
  • expdp dmp 导出不完整导入ORA-39059 ORA-39246 故障抢救数据
  • 基于 Node.js 与 Tesseract.js 的验证码识别系统设计与实现
  • 用 Rust 和 Leptess 构建轻量级验证码识别工具
  • 12.2 HTML
  • WIN11系统环境松灵机器人SCOUT2.0底盘CAN通信控制测试
  • 软工团队作业4
  • 使用Frp+Caddy把https映射到内网的web服务
  • 刷题日记—前缀和