一、什么是中间件?
-
中间件 是一种装配到 ASP.NET Core 应用程序请求处理管道中的软件组件,用于处理 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(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. 通过独立类定义中间件(推荐)
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, "百小僧");
四、中间件的顺序
- 中间件的执行顺序 是至关重要的,它决定了每个中间件在请求处理管道中的位置。中间件按照它们在代码中注册的顺序依次执行,先注册的中间件先执行,后注册的中间件后执行。因此,顺序的安排会直接影响到应用的行为。
五、依赖注入/解析服务
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()
之间的中间件中调用,才能确保路由信息已经解析。