Day10:ASP.NET Core 管道与中间件

一、今日学习目标

  1. 理解 请求管道 执行顺序
  2. 掌握 Use / Run / Map 区别
  3. 学会 自定义中间件
  4. 写两个企业常用中间件:
    • 请求日志中间件
    • 简单权限校验中间件

二、核心面试题 + 标准答案

1. 什么是 ASP.NET Core 管道?

答案: HTTP 请求从进入到响应离开,经过的一系列中间件组件 叫请求管道。请求依次经过中间件,响应原路返回,类似俄罗斯套娃

2. Use / Run / Map 区别(高频必问)

  • Use :注册中间件,可以交给下一个 (调用 await next()
  • Run终端中间件 ,执行后直接返回,不往后走
  • Map :按路径分支,匹配某个路径才执行

3. 中间件执行顺序?

**答案:**配置顺序 = 执行顺序。先注册的先接收请求,后响应。

4. 中间件 vs 过滤器?

  • 中间件:全局,针对所有请求,更底层
  • 过滤器:针对 Controller/Action,属于 MVC 框架
  • 性能:中间件更高

5. 中间件生命周期?

答案: 默认 Singleton ,所以不要在中间件里写 Scoped 服务 ,要用 IServiceProvider 手动创建作用域获取。

6. 自定义中间件两种方式?

  1. 匿名委托(app.Use
  2. 独立类(RequestMiddleware,标准企业写法)

三、核心语法速记

cs 复制代码
// 分支
app.Map("/test", builder => builder.Run(...));

// 短路
app.Run(async context => await context.Response.WriteAsync("end"));

// 标准中间件
app.Use(async (context, next) =>
{
    // 请求前
    await next();
    // 响应后
});

四、Day10 实战练习(必须完成)

练习 1:请求日志中间件

  • 记录:请求路径、方法、耗时、状态码
  • 输出到控制台 / Serilog

练习 2:简单权限校验中间件

  • 判断请求头是否包含 Token: admin
  • 没有则直接返回 401
  • 有则继续执行后续管道

四、练习代码

WeatherController.cs

cs 复制代码
[ApiController]
[Route("api/[controller]")]
public class WeatherController : ControllerBase
{
    [HttpGet]
    public IActionResult Get()
    {
        return Ok("正常接口数据");
    }

    [HttpPost("login")]
    public IActionResult Login()
    {
        return Ok("登录成功,返回 Token:admin");
    }
}

appsettings.json

cs 复制代码
"Serilog": {
  "MinimumLevel": {
    "Default": "Debug",
    "Override": {
      "Microsoft": "Warning",
      "System": "Warning"
    }
  },
  "WriteTo": [
    { "Name": "Console" },
    {
      "Name": "File",
      "Args": {
        //文件保存路径及文件名
        "path": "Logs/log-.txt",
        //滚动策略:以天为单位,每天生成一个新日志文件,如 log-20260410.log
        "rollingInterval": "Day",
        //输出模板:2026-04-10 12:54:27 [DBG] 调试日志:服务启动成功
        "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss}[{Level:u3}]{Message:lj}{NewLine}{Exception}"
      }
    }
  ]
}

Program.cs

cs 复制代码
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();

var app = builder.Build();

// ==========================
// 1. 日志中间件(Use)
//  记录:请求路径、方法、耗时、状态码
//  输出到控制台 / Serilog
// ==========================
app.Use(async (context, next) =>
{
    // 请求前
    var path = context.Request.Path;
    var method = context.Request.Method;
    var start = DateTime.UtcNow;    //开始时间

    Console.WriteLine($"[请求进入] {method} {path}");

    await next();// 调用下一个中间件

    // 响应后
    var cost = (DateTime.UtcNow - start).TotalMilliseconds; //计算耗时
    var code = context.Response.StatusCode;                 //响应状态
    Console.WriteLine($"[请求结束] {method} {path} | 状态码:{code} | 耗时:{cost:F2}ms");
});

// ==========================
// 2. 权限校验中间件
//  判断请求头是否包含 Token: admin
//  没有则直接返回 401
//  有则继续执行后续管道
// ==========================
app.Use(async (context, next) =>
{
    var path = context.Request.Path;
    
    // 登录接口不校验
    if (path.StartsWithSegments("/api/weather/login"))  //StartsWithSegments:用于‌按路径段(segment)精确匹配 URL 前缀‌的方法,常用于中间件、路由或 API 版本控制等场景。
    {
        await next();
        return;
    }

    var token = context.Request.Headers["Token"].FirstOrDefault();

    if (token != "admin") 
    {
        context.Response.StatusCode = 401;
        await context.Response.WriteAsync("无权限,请在请求头带 Token:admin");
        return; //短路不往后走
    }
    await next();

});


// ==========================
// 3. Map 分支演示
// ==========================
app.Map("/begin", x =>
{
    x.Run(async c =>
    {
        await c.Response.WriteAsync("Hello from Map");
    });
});

// ==========================
// 4. Run 终端中间件
// ==========================
app.Map("/end", x =>
{
    x.Run(async c => await c.Response.WriteAsync("This is the end."));
});

app.MapControllers();
app.Run();
相关推荐
阿昌喜欢吃黄桃3 天前
RocketMq事务消息原理
java·中间件·消息队列·rocketmq·mq
半夜修仙4 天前
延迟队列的介绍及常见问题
java·数据库·中间件·rabbitmq
手握风云-4 天前
一条消息的旅程:RabbitMQ 学习与实践(一)
中间件·rabbitmq
RH2312115 天前
2026.6.8Linux
java·数据库·中间件
理人综艺好会6 天前
双Token机制在实际项目中的应用与实践
中间件·token
番茄去哪了6 天前
神领物流面试题(一)
java·大数据·中间件
念何架构之路6 天前
消息中间件
中间件
都说名字长不会被发现6 天前
Spring Boot Starter 中间件账号密码加密方案设计与实现
java·spring boot·后端·中间件
瀚高PG实验室7 天前
java中间件无法连接数据库
java·数据库·中间件·瀚高数据库
之歆7 天前
Day11_Express 深入解析:从中间件到项目实战
中间件·express