ASP.NET Core 中间件

devtools/2024/12/22 9:11:08/

一、什么是中间件

  • 中间件 是一种装配到 ASP.NET Core 应用程序请求处理管道中的软件组件,用于处理 HTTP 请求和响应。
    在这里插入图片描述

  • 每个中间件组件可以:

    • 选择是否将请求传递到下一个中间件:通过调用 next() 或者不调用 next() 来决定是否将请求继续传递给下一个中间件

    • 在传递前后执行某些操作:可以在将请求传递给下一个中间件之前或者之后执行一些自定义逻辑。

    • 请求委托用于生成请求管道。 请求委托处理每个 HTTP 请求。

  • 中间件的作用中间件比筛选器更底层和更上游,是一种性能更高、适用范围更广的面向切面技术,可处理如网关、URL 转发、限流等复杂操作。
    在这里插入图片描述

二、常见的中间件

1. 所有请求返回同一个结果

  • 这个中间件会对所有请求返回相同的响应内容,不论请求的 URL 是什么。
app.Run(async context =>
{await context.Response.WriteAsync("Hello world!");  // 所有请求的响应内容
});

2. 拦截所有请求

  • 通过 app.Use 方法可以拦截所有请求,并在处理请求时进行一些操作,例如设置统一的 HTTP 头信息。
app.Use(async (context, next) =>
{context.Response.Headers["framework"] = "Furion";  // 设置自定义响应头await next.Invoke();  // 将请求传递给下一个中间件
});

3. 特定路由中间件

  • 这个中间件仅对特定的 URL 路径进行处理,例如 /hello
app.Map("/hello", app => {app.Run(async context =>{await context.Response.WriteAsync("Map Test 1");  // 仅对 /hello 路径进行处理});
});

4. 嵌套路由中间件

  • 中间件可以嵌套使用,根据不同的路由层级进行处理,例如处理 /level1/level2a/level1/level2b 路径的请求。
app.Map("/level1", level1App => {level1App.Map("/level2a", level2AApp => {level2AApp.Run(async context =>{await context.Response.WriteAsync("Map Level 2A");});});level1App.Map("/level2b", level2BApp => {level2BApp.Run(async context =>{await context.Response.WriteAsync("Map Level 2B");});});
});

三、自定义中间件

1. 通过 app.Use 定义中间件

  • 这是定义中间件的最简单方式,但通常不推荐用于复杂场景。可以直接在 app.Use 内部编写中间件逻辑。
app.Use(async (context, next) =>
{var cultureQuery = context.Request.Query["culture"];  // 获取请求中的 culture 查询参数if (!string.IsNullOrWhiteSpace(cultureQuery)){var culture = new CultureInfo(cultureQuery);CultureInfo.CurrentCulture = culture;  // 设置当前文化信息CultureInfo.CurrentUICulture = culture;  // 设置当前 UI 文化信息}await next(context);  // 将请求传递给下一个中间件
});

2. 通过独立类定义中间件(推荐)

  • 创建一个独立的中间件类,并通过 app.UseMiddleware 方法来使用这个中间件。这种方式便于复用和维护。
public class RequestCultureMiddleware
{private readonly RequestDelegate _next;public RequestCultureMiddleware(RequestDelegate next){_next = next;}public async Task InvokeAsync(HttpContext context){var cultureQuery = context.Request.Query["culture"];  // 从查询字符串中获取文化信息if (!string.IsNullOrWhiteSpace(cultureQuery)){var culture = new CultureInfo(cultureQuery);CultureInfo.CurrentCulture = culture;  // 设置当前线程的文化信息CultureInfo.CurrentUICulture = culture;  // 设置当前线程的 UI 文化信息}await _next(context);  // 将请求传递给下一个中间件}
}// 扩展方法
public static class RequestCultureMiddlewareExtensions
{public static IApplicationBuilder UseRequestCulture(this IApplicationBuilder builder){return builder.UseMiddleware<RequestCultureMiddleware>();  // 使用自定义中间件}
}// 使用中间件
app.UseRequestCulture();

3. 配置更多参数

  • 中间件可以接收更多的构造参数,包括依赖注入的服务和普通参数。
public class RequestCultureMiddleware
{private readonly RequestDelegate _next;private readonly ILogger<RequestCultureMiddleware> _logger;public RequestCultureMiddleware(RequestDelegate next, ILogger<RequestCultureMiddleware> logger, int age, string name){_next = next;_logger = logger;}public async Task InvokeAsync(HttpContext context){_logger.LogInformation("Executing middleware for {Name} who is {Age} years old.", name, age);  // 使用日志记录操作信息await _next(context);  // 继续执行下一个中间件}
}// 扩展方法
public static class RequestCultureMiddlewareExtensions
{public static IApplicationBuilder UseRequestCulture(this IApplicationBuilder builder, int age, string name){return builder.UseMiddleware<RequestCultureMiddleware>(new object[] { age, name });  // 传递参数到中间件}
}// 使用中间件
app.UseRequestCulture(30, "百小僧");

四、中间件的顺序

  • 中间件的执行顺序 是至关重要的,它决定了每个中间件在请求处理管道中的位置。中间件按照它们在代码中注册的顺序依次执行,先注册的中间件先执行,后注册的中间件后执行。因此,顺序的安排会直接影响到应用的行为。

五、依赖注入/解析服务

  • 中间件可以通过构造函数注入服务,也可以在中间件内部通过 HttpContext.RequestServices 解析服务。这样可以在中间件中使用已经注册的服务。
public class RequestCultureMiddleware
{private readonly RequestDelegate _next;private readonly ILogger<RequestCultureMiddleware> _logger;public RequestCultureMiddleware(RequestDelegate next, ILogger<RequestCultureMiddleware> logger){_next = next;_logger = logger;}public async Task InvokeAsync(HttpContext context){var repository = context.RequestServices.GetService<IRepository>();  // 解析服务await _next(context);  // 继续执行下一个中间件}
}

六、删除特定的 HTTP 响应头

  • 可以通过中间件删除或修改 HTTP 响应头。例如,删除默认添加的响应头信息。
app.Use(async (context, next) =>
{context.Response.Headers.Remove("Server");  // 删除 Server 响应头await next();  // 继续执行下一个中间件
});

七、常见问题

  • 中间件中获取终点路由的特性或其他信息时,可以通过以下方式实现:
var endpointFeature = context.Features.Get<IEndpointFeature>();  // 获取终点特性
var attribute = endpointFeature?.Endpoint?.Metadata?.GetMetadata<YourAttribute>();  // 获取自定义的特性
  • 需要注意的是,这种操作必须在 UseRouting()UseEndpoints() 之间的中间件中调用,才能确保路由信息已经解析。

http://www.ppmy.cn/devtools/109234.html

相关文章

IP学习——oneday

1.什么是网络&#xff1f;为什么需要网络&#xff1f; 空间&#xff0c;时间&#xff1b;传统的邮件传输要考虑到距离&#xff0c;网络解决了空间距离&#xff08;太远&#xff09;、解决了时间问题&#xff08;旧音乐等&#xff09; 云:面向客户的虚拟化服务 运营商公司主营…

SQL 支持使用 GROUP BY多个列

SQL 语言支持使用 GROUP BY 子句对多个列进行分组。当你对多个列进行分组时&#xff0c;SQL 会根据这些列的组合值来分组数据。这意味着只有当所有指定的列在多行中具有相同的值时&#xff0c;这些行才会被分组在一起。 语法 SELECT column1, column2, AGGREGATE_FUNCTION(co…

【JUC】同步器(AQS原理、ReentrantLock原理、ConcurrentHashMap原理)

文章目录 一、AQS原理1.1 AQS简介1.2 AQS原理1.3 CLH队列1.4 ASQ的设计1.4.1 设计原理1.4.2 state 设计1.4.3 封装线程的 Node 节点中 waitStatus 设计1.4.4 阻塞恢复设计1.4.5 队列设计为什么队列要设计成双向链表&#xff1f; 1.5 自定义同步器 二、**ReentrantLock 原理**2.…

当小程序遭遇攻击或超出流量峰值时:SCDN边缘加速的高效防护策略!

在数字化时代&#xff0c;小程序因其便捷性和丰富的功能而备受用户喜爱&#xff0c;但这也使其成为了网络攻击的目标之一。DDoS攻击、CC攻击等不仅会影响小程序的正常运行&#xff0c;还会损害用户体验和品牌形象。在这种情况下&#xff0c;选择合适的安全防护措施至关重要。边…

ffmpeg的安装和使用教程

在Linux上安装和使用FFmpeg可以方便地完成音视频的编码、解码、转码等操作。以下是详细的安装和使用教程。 安装FFmpeg FFmpeg的安装方法会因为不同的Linux发行版有所不同。下面是几种常见的安装方法&#xff1a; Ubuntu/Debian 打开终端&#xff0c;更新包列表并安装FFmpe…

springboot绘画艺术品在线交易商城管理系统---附源码87862

摘 要 随着互联网的快速发展&#xff0c;艺术品交易逐渐向线上平台转移&#xff0c;为了满足用户对绘画艺术品的需求&#xff0c;开发一个高效、安全、易用的在线交易商城管理系统变得尤为重要。 本文首先介绍了绘画艺术品在线交易商城管理系统的背景和重要性。然后&#xff0…

urllib与requests爬虫简介

urllib与requests爬虫简介 – 潘登同学的爬虫笔记 文章目录 urllib与requests爬虫简介 -- 潘登同学的爬虫笔记第一个爬虫程序 urllib的基本使用Request对象的使用urllib发送get请求实战-喜马拉雅网站 urllib发送post请求 动态页面获取数据请求 SSL证书验证伪装自己的爬虫-请求头…

golang fmt.Printf中 %q

在 Go 语言中&#xff0c;fmt.Printf 函数用于格式化输出&#xff0c;其中 %q 是一个非常有用的格式动词&#xff0c;用于在字符串或字节切片周围加上引号。这对于调试和显示字符串内容时特别有用&#xff0c;因为它会显示出字符串的原始形式&#xff0c;包括转义字符。 以下是…