用三张图片详解Asp.Net 全生命周期
Asp.Net 作为一个成熟的 Web 框架,其请求处理管道(Pipeline)是每个开发者必须掌握的核心知识。很多初学者只停留在"写 Controller → 返回 JSON"的层面,却不知道一个 HTTP 请求从进入服务器到返回响应,中间经历了多少个阶段、哪些组件参与、哪些扩展点可以插入自定义逻辑。本文用三张关键图片,从宏观到微观,彻底拆解 Asp.Net(这里以 .NET Core / .NET 5+ 为主,兼顾传统 Framework 的差异)的全生命周期。### 第一张图:宏观视角 ------ 从 Kestrel 到中间件管道外链图片转存中...(img-jarPQ4gB-1785920832408)核心流程阶段:1. 客户端发起 HTTP 请求 → 到达服务器监听端口(默认 Kestrel 或 IIS)2. 服务器接收 → 将原始字节流解析为 HttpContext 对象3. 中间件管道 → 一系列注册的中间件依次处理请求(这是最核心的部分)4. 路由终结点 → 匹配 URL 到具体的 Controller/Action 或 Minimal API5. 执行过滤器 → 在 Action 前后执行(如认证、日志、缓存)6. 生成响应 → 返回结果,反向穿过管道代码示例:最小化中间件管道 csharp// Program.cs - 最小化 Asp.Net 应用var builder = WebApplication.CreateBuilder(args);var app = builder.Build();// 自定义第一个中间件:记录请求时间app.Use(async (context, next) =>{ var start = DateTime.UtcNow; await next(); // 调用下一个中间件 var elapsed = DateTime.UtcNow - start; Console.WriteLine($"请求耗时:{elapsed.TotalMilliseconds} ms");});// 自定义第二个中间件:检查请求头app.Use(async (context, next) =>{ if (!context.Request.Headers.ContainsKey("X-Api-Key")) { context.Response.StatusCode = 401; await context.Response.WriteAsync("缺少 API Key"); return; // 短路,不再执行后续中间件 } await next();});// 终结点路由app.MapGet("/", () => "Hello World!");app.Run(); // 启动应用关键点: 中间件是一个"洋葱模型",请求从外层进入,层层向内,响应再反向出来。每个中间件都可以决定是否短路(不调用 next()),这常用于认证、限流等场景。---### 第二张图:微观视角 ------ 中间件管道的内部排序外链图片转存中...(img-pLsU28Sk-1785920832410)为什么顺序如此重要? 假设你注册了 UseAuthentication 和 UseAuthorization,如果你把授权放在认证之前,那么未认证用户也能通过授权检查(因为用户为空),这会导致严重的安全漏洞。官方推荐的顺序是:1. UseExceptionHandler // 异常捕获2. UseHsts // HTTPS 强制3. UseHttpsRedirection // HTTP → HTTPS4. UseStaticFiles // 静态文件5. UseRouting // 路由匹配6. UseCors // 跨域7. UseAuthentication // 认证8. UseAuthorization // 授权9. UseEndpoints // 终结点执行代码示例:显式控制中间件顺序 csharpapp.UseExceptionHandler("/error"); // 异常处理app.UseHttpsRedirection(); // HTTPSapp.UseStaticFiles(); // wwwroot 静态文件app.UseRouting(); // 路由匹配(必须早于终结点)app.UseCors("MyPolicy"); // CORS 策略app.UseAuthentication(); // 解析用户身份app.UseAuthorization(); // 权限检查app.UseEndpoints(endpoints =>{ endpoints.MapControllers(); // 映射所有 Controller endpoints.MapGet("/health", () => Results.Ok()); // 健康检查});实战陷阱: 如果 UseStaticFiles 放在 UseRouting 之后,静态文件请求也会被路由匹配,虽然最终能工作,但会多消耗一次路由计算。更严重的是,如果你在路由后加了认证中间件,静态文件也会要求认证,导致图片、CSS 无法加载。所以顺序是性能和安全的关键。---### 第三张图:请求在 MVC 内部的旅程外链图片转存中...(img-jUym9wv9-1785920832410)当请求匹配到 Controller 后,内部又有多个阶段:1. 路由匹配 → 确定 Controller 和 Action2. Model Binding → 将请求数据(Query/Form/JSON)绑定到 Action 参数3. Model Validation → 检查参数是否满足 DataAnnotations4. Action Filters → 执行自定义过滤器(如 [Authorize]、[ValidateAntiForgeryToken])5. Action 执行 → 调用业务逻辑,返回 IActionResult6. Result Filters → 对结果进行包装(如统一响应格式)7. 序列化 → 将对象转为 JSON/XML 并写入响应代码示例:自定义 Action Filter 实现日志记录 csharppublic class LogActionFilter : IAsyncActionFilter{ public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) { // 执行前 var controller = context.Controller.GetType().Name; var action = context.ActionDescriptor.DisplayName; Console.WriteLine($"[PRE] 即将执行 {controller}.{action}"); // 记录请求参数 foreach (var arg in context.ActionArguments) { Console.WriteLine($" 参数: {arg.Key} = {arg.Value}"); } // 执行 Action var resultContext = await next(); // 执行后 var status = resultContext.Result is ObjectResult obj ? obj.StatusCode : 200; Console.WriteLine($"[POST] 执行完成,状态码: {status}"); }}// 注册到 ServiceCollectionbuilder.Services.AddScoped<LogActionFilter>();// 应用到某个 Controller 或全局[ServiceFilter(typeof(LogActionFilter))]public class WeatherController : ControllerBase{ [HttpGet] public IActionResult Get() { return Ok(new { Temperature = 25, Condition = "Sunny" }); }}注意点: Filter 和中间件是不同的扩展机制。中间件在管道层面工作,可以处理静态文件、认证等;Filter 只在 MVC 内部,专注于 Action 执行前后的逻辑。如果你需要处理所有请求(包括静态文件),用中间件;如果只处理业务 Action,用 Filter。---### 总结通过三张图,我们从宏观到微观完整走了一遍 Asp.Net 的生命周期:| 层级 | 关键组件 | 扩展方式 ||------|----------|----------|| 服务器层 | Kestrel/IIS | 无(框架内置) || 管道层 | 中间件 | app.Use... || 路由层 | Routing | 属性路由/约定路由 || MVC 层 | Filters | 实现 IAsyncActionFilter 等 || 结果层 | 序列化 | 自定义 IOutputFormatter |核心心法: 请求是一个"洋葱",每一层都可以观察、修改、短路。理解生命周期,不是背流程图,而是知道"在哪个环节插入代码最合适"。比如:想记录所有 API 耗时 → 用中间件;想跳过某些 Action 的验证 → 用 Action Filter;想统一返回格式 → 用 Result Filter。掌握这些,你就能从"会用框架"进阶到"驾驭框架"。