什么是中间件:
应用程序管道中用来处理请求和响应的组件。
中间件是一个请求委托(public delegate Task RequestDelegate(HttpContext context))的实例,所以中间件的本质是一个方法,参数是HttpContext,返回参数是一个task,每个中间件根据不同的方法,可以决定是否将请求传递给管道中的下个组件,也可以在执行管道中下个请求的前后都处理业务逻辑。
注册中间件的方法
中间件由管道来注册,ApplicationBuilder来通过注册中间件来构建一个请求管道。构建中间件的方法有:
Run
用run方法注册的中间件,执行之后,不会再执行下一个中间件,所以这个中间件也叫终端中间件
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
//第一个中间件
app.Run(async (context) =>
{
context.Response.ContentType = "text/plain;charset=utf-8";//防止中文乱码
await context.Response.WriteAsync("第一个中间件输出你好~");
});
//第二个中间件
app.Run(async (context) =>
{
await context.Response.WriteAsync("第二个中间件输出你好~");
});
}
它只会执行第一个,不会执行第二个中间件
Use
use方法的参数是一个委托实例,第一个参数是HttpContext,这是待处理的请求上下文,第二个参数是next,下一个中间件,可以用next.Invoke()调用下一个中间件,并且可以在调用下一个中间件之后/之前对HttpContext进行逻辑处理。
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
//第一个中间件
app.Use(async (context, next) =>
{
context.Response.ContentType = "text/plain;charset=utf-8";//防止中文乱码
await context.Response.WriteAsync($"第一个中间件输出你好~{Environment.NewLine}");
await context.Response.WriteAsync($"下一个中间件执行前执行===>{Environment.NewLine}");
await next.Invoke();
await context.Response.WriteAsync($"下一个中间件执行后执行<==={Environment.NewLine}");
});
//第二个中间件
app.Use(async (context,next) =>
{
await context.Response.WriteAsync($"第二个中间件输出你好~{Environment.NewLine}");
});
}
如果没有调用next.Invoke(),会造成管道短路,后面的中间件都不会执行
Map
当业务复杂的时候,我们可以考虑把不同的业务分支交给不同的管道来处理,Map根据请求的路径的匹配项来创建不同的管道分支。如果请求的路径以给定路径开头,则执行这个分支。
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// 依赖注入
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}
/// <summary>
/// 配置用户分支管道,处理以url以/userinfo开头的请求
/// </summary>
/// <param name="app"></param>
private static void UserinfoConfigure(IApplicationBuilder app)
{
app.Use(async (context, next) =>
{
await context.Response.WriteAsync($"处理用户业务,{Environment.NewLine}");
await next.Invoke();
});
app.Run(async (context) => { await context.Response.WriteAsync("用户业务处理完成~"); });
}
/// <summary>
/// 配置产品分支管道,处理以url以/product开头的请求
/// </summary>
/// <param name="app"></param>
private static void ProductConfigure(IApplicationBuilder app)
{
app.Use(async (context, next) =>
{
await context.Response.WriteAsync($"处理产品业务");
await next.Invoke();
});
}
// 配置请求处理管道
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
//防止中文乱码
app.Use(async (context,next) =>
{
context.Response.ContentType = "text/plain;charset=utf-8";
await next.Invoke();
});
app.Map("/userinfo", UserinfoConfigure);
app.Map("/product", ProductConfigure);
app.Run(async context =>
{
await context.Response.WriteAsync("主管道处理其他业务");
});
}
}
MapWhen
MapWhen和Map的思想比较接近,MapWhen根据自定义条件来创建请求管道分支,并将请求映射到分支。
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// 依赖注入
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}
/// <summary>
/// 配置分支管道,处理以url中有包含/userinfo的请求
/// </summary>
/// <param name="app"></param>
private static void UserinfoConfigure(IApplicationBuilder app)
{
app.Use(async (context, next) =>
{
await context.Response.WriteAsync($"处理用户业务,{Environment.NewLine}");
await next.Invoke();
});
app.Run(async (context) => { await context.Response.WriteAsync("用户业务处理完成~"); });
}
/// <summary>
/// 配置分支管道,处理以查询参数有name的请求
/// </summary>
/// <param name="app"></param>
private static void HNameConfigure(IApplicationBuilder app)
{
app.Use(async (context, next) =>
{
await context.Response.WriteAsync($"查询参数包含name,值为:{context.Request.Query["name"]}");
await next.Invoke();
});
}
// 配置请求处理管道
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
//防止中文乱码
app.Use(async (context,next) =>
{
context.Response.ContentType = "text/plain;charset=utf-8";
await next.Invoke();
});
app.MapWhen(context => context.Request.Query.ContainsKey("name"), HNameConfigure);
app.MapWhen(context => context.Request.Path.Value.ToString().Contains("/userinfo"), UserinfoConfigure);
app.Run(async context =>
{
await context.Response.WriteAsync("主管道处理其他业务");
});
}
}