摘要:处理请求,将请求传递给下一个中间件,或者中断管道(短路)。中间件可以在下一个中间件执行前后执行操作,如日志、认证、错误处理等。中间件按照在 Program.cs 中添加的顺序执行。
中间件是 HTTP 请求管道中的一个组件,可以:
处理请求,
将请求传递给下一个中间件,
或者中断管道(短路)。
中间件可以在下一个中间件执行前后执行操作,如日志、认证、错误处理等。
中间件按照在 Program.cs 中添加的顺序执行。
2. 如何配置中间件管道(在 Program.cs / Startup.cs 中)?
在 ASP.NET Core 6+(最小主机模型)中,中间件在 Program.cs 中添加:
var builder = WebApplication.CreateBuilder(args);var app = builder.Build;
app.UseMiddleware
app.UseRouting;
app.UseEndpoints(endpoints => { endpoints.MapControllers; });
app.Run;
- 在旧版本(例如 .NET Core 3.1)中,使用 Startup.cs:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseMiddleware
app.UseRouting;
}
3. app.Use、app.UseMiddleware、app.Run 和 app.Map 的区别**
方法
说明
app.Use 添加可以调用 next 的中间件 app.UseMiddleware 添加自定义中间件类 app.Run 终止中间件,不调用 next,结束管道 app.Map 根据 URL 路径分支管道(如 /api)示例:
app.Use(async (context, next) => {await next; // 调用下一个中间件
});
app.Run(async context => {
await context.Response.WriteAsync("Hello World"); // 终止管道
});
创建一个类,构造函数接收 RequestDelegate,包含 Invoke 或 InvokeAsync 方法。
public class MyCustomMiddleware{
private readonly RequestDelegate _next;
public MyCustomMiddleware(RequestDelegate next) => _next = next;
public async Task InvokeAsync(HttpContext context)
{
// 前置逻辑
await _next(context);
// 后置逻辑
}
}
RequestDelegate 是一个委托,表示管道中的下一个中间件。
public delegate Task RequestDelegate(HttpContext context);中间件按添加顺序执行,顺序会影响行为。
例如: app.UseAuthentication必须在授权之前。日志、错误处理、安全中间件应放在管道前面。
if (!context.User.Identity.IsAuthenticated){
context.Response.StatusCode = 401;
return; // 短路
}
await next; // 仅认证通过时调用
app.UseStaticFiles用于从 wwwroot 提供静态文件。
必须在路由或 endpoints 之前添加,否则静态文件会被控制器逻辑处理。
9. 如何使用中间件处理异常(UseExceptionHandler, UseDeveloperExceptionPage)
UseDeveloperExceptionPage:开发环境显示详细错误。
UseExceptionHandler("/Error"):生产环境自定义错误页面。
也可内联处理:
app.UseExceptionHandler(errorApp => {errorApp.Run(async context => {
context.Response.StatusCode = 500;
await context.Response.WriteAsync("An error occurred");
});
});
app.UseHttpsRedirection;将 HTTP 请求重定向到 HTTPS。
应在认证或路由之前添加。
HTTPS 端口可在 launchSettings.json 或 appsettings.json 配置。
11. 如何使用自定义文件提供程序或选项(如缓存、目录浏览)提供静态文件?**
app.UseStaticFiles(new StaticFileOptions{
FileProvider = new PhysicalFileProvider(Path.Combine(env.ContentRootPath, "MyFiles")),
RequestPath = "/Files",
OnPrepareResponse = ctx => {
ctx.Context.Response.Headers.Append("Cache-Control", "public,max-age=600");
}
});
app.UseDirectoryBrowser(new DirectoryBrowserOptions
{
FileProvider = new PhysicalFileProvider("path"),
RequestPath = "/browse"
});
类型
说明
终止(Terminal) 结束管道,不调用 next,如 app.Run 非终止(Non-Terminal) 调用 next,允许后续中间件执行,如 app.Use app.UseAuthentication;验证用户身份app.UseAuthorization;应用策略/角色顺序:路由后,endpoints 前
builder.Services.AddCors(options => {options.AddPolicy("MyPolicy", policy => {
policy.WithOrigins("https://example.com")
.AllowAnyHeader
.AllowAnyMethod;
});
});
使用中间件: app.UseCors("MyPolicy");,应在路由/endpoints 之前public class TimingMiddleware
{
private readonly RequestDelegate _next;
public TimingMiddleware(RequestDelegate next) => _next = next;
public async Task InvokeAsync(HttpContext context)
{
var sw = Stopwatch.StartNew;
await _next(context);
sw.Stop;
Console.WriteLine($"Request took {sw.ElapsedMilliseconds} ms");
}
}
欢迎各位票友补充。下一节我们来中间件。
来源:opendotnet