[netcore] ASP.NET Core 中间件

Posted 厦门德仔

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[netcore] ASP.NET Core 中间件相关的知识,希望对你有一定的参考价值。

基本概念

中间件是一种装配到应用管道以处理请求和响应的软件。 每个组件:

选择是否将请求传递到管道中的下一个组件。
可在管道中的下一个组件前后执行工作。
请求委托用于生成请求管道。 请求委托处理每个 HTTP 请求。

使用 RunMap 和 Use 扩展方法来配置请求委托。 可将一个单独的请求委托并行指定为匿名方法(称为并行中间件),或在可重用的类中对其进行定义。 这些可重用的类和并行匿名方法即为中间件,也叫中间件组件。 请求管道中的每个中间件组件负责调用管道中的下一个组件,或使管道短路。 当中间件短路时,它被称为“终端中间件”,因为它阻止中间件进一步处理请求。

将 HTTP 处理程序和模块迁移到 ASP.NET Core 中间件介绍了 ASP.NET Core 和 ASP.NET 4.x 中请求管道之间的差异,并提供了更多的中间件示例。

WHY

中间件是ASP.NET Core的核心组件:

MVC框架,响应缓存,身份验证,CORS,Swagger等都是内置中间件。

什么是中间件

1.广义上来讲:Tomcat,WebLogic,Redis,IIS;狭义上来讲,ASP.NET Core中的中间件指ASP.NET Core 中的一个组件。
2.中间件由前逻辑,next,后逻辑3部分组成,前逻辑为第一段要执行的逻辑代码,next为指向下一个中间件的调用,后逻辑为从下一个中间件执行返回所执行的逻辑代码。每个HTTP请求都要经历一系列中间件的处理,每个中间件对于请求特定的处理后,再转到下一个中间件,最终的业务逻辑代码执行完成后,响应的内容也会按照处理的相反顺序进行处理,然后形成HTTP响应报文返回给客户端。
3.中间件组成一个管道,整个ASP.NET CORE的执行过程就是HTTP请求和响应按照中间件组装的顺序再中间之间流转的过程,开发人员可以对组成管道的中间件按照需要进行自由组合

中间件的三个概念

Map,Use和Run.Map用来定义一个管道可以处理那些请求,Use和Run来定义管道,一个管道由若干个use和一个Run组成,每个Use引入一个中间件,而run是用来执行最终核心的应用逻辑

每个委托均可在下一个委托前后执行操作。 应尽早在管道中调用异常处理委托,这样它们就能捕获在管道的后期阶段发生的异常。

尽可能简单的 ASP.NET Core 应用设置了处理所有请求的单个请求委托。 这种情况不包括实际请求管道。 调用单个匿名函数以响应每个 HTTP 请求。

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.Run(async context =>

    await context.Response.WriteAsync("Hello world!");
);

app.Run();

用 Use 将多个请求委托链接在一起。 next 参数表示管道中的下一个委托。 可通过不调用 next 参数使管道短路。 通常可在 next 委托前后执行操作,如以下示例所示:

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.Use(async (context, next) =>

    // Do work that can write to the Response.
    await next.Invoke();
    // Do logging or other work that doesn't write to the Response.
);

app.Run(async context =>

    await context.Response.WriteAsync("Hello from 2nd delegate.");
);

app.Run();

当委托不将请求传递给下一个委托时,它被称为“让请求管道短路”。 通常需要短路,因为这样可以避免不必要的工作。 例如,静态文件中间件可以处理对静态文件的请求,并让管道的其余部分短路,从而起到终端中间件的作用。 如果中间件添加到管道中,且位于终止进一步处理的中间件前,它们仍处理 next.Invoke 语句后面的代码。 不过,请参阅下面有关尝试对已发送的响应执行写入操作的警告
Run 委托不会收到 next 参数。 第一个 Run 委托始终为终端,用于终止管道。 Run 是一种约定。 某些中间件组件可能会公开在管道末尾运行的 Run[Middleware] 方法:

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.Use(async (context, next) =>

    // Do work that can write to the Response.
    await next.Invoke();
    // Do logging or other work that doesn't write to the Response.
);

app.Run(async context =>

    await context.Response.WriteAsync("Hello from 2nd delegate.");
);

app.Run();

在前面的示例中,Run 委托将 “Hello from 2nd delegate.” 写入响应,然后终止管道。 如果在 Run 委托之后添加了另一个 Use 或 Run 委托,则不会调用该委托。

中间件顺序

下图显示了 ASP.NET Core MVC 和 Razor Pages 应用的完整请求处理管道。 你可以在典型应用中了解现有中间件的顺序,以及在哪里添加自定义中间件。 你可以完全控制如何重新排列现有中间件,或根据场景需要注入新的自定义中间件

图中的“终结点”中间件为相应的应用类型(MVC 或 Razor Pages)执行筛选器管道。

上一个图中的路由中间件显示在以下静态文件中。 这是通过显式调用 app.UseRouting 实现项目模板的顺序。 如果不调用 app.UseRouting,路由中间件将默认在管道开头运行。 有关详细信息,请参阅路由。

对中间件管道进行分支

Map 扩展用作约定来创建管道分支。 Map 基于给定请求路径的匹配项来创建请求管道分支。 如果请求路径以给定路径开头,则执行分支。

做个简单测试:

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

//app.MapGet("/", () => "Hello World!");

//app.MapGet("/test", () => "gdh");
app.Map("/test",async(appbuilder) => 
    appbuilder.Use(async (context, next) => 
        context.Response.ContentType = "text/html";
        await context.Response.WriteAsync("1 start<br/>");
        await next.Invoke();
        await context.Response.WriteAsync("1 end<br/>");
    );

    appbuilder.Use(async (context, next) => 
        await context.Response.WriteAsync("2 start<br/>");
        await next.Invoke();
        await context.Response.WriteAsync("2 end<br/>");
    );

    appbuilder.Run(async context => 
        await context.Response.WriteAsync("Run <br/>");
    );


);


app.Run();

运行效果:

同样支持嵌套,请自行验证。

内置中间件

ASP.NET Core 附带以下中间件组件。 “顺序”列提供备注,以说明中间件在请求处理管道中的放置,以及中间件可能会终止请求处理的条件。 如果中间件让请求处理管道短路,并阻止下游中间件进一步处理请求,它被称为“终端中间件”。 若要详细了解短路,请参阅使用 IApplicationBuilder 创建中间件管道部分。

中间件描述顺序
身份验证提供身份验证支持。在需要 HttpContext.User 之前。 OAuth 回叫的终端。
授权提供身份验证支持。紧接在身份验证中间件之后。
Cookie 策略跟踪用户是否同意存储个人信息,并强制实施 cookie 字段(如 secure 和 SameSite)的最低标准。在发出 cookie 的中间件之前。 示例:身份验证、会话、MVC (TempData)。
CORS配置跨域资源共享。在使用 CORS 的组件之前。 由于此错误,UseCors 当前必须在 UseResponseCaching 之前运行。
DeveloperExceptionPage生成一个页面,其中包含的错误信息仅适用于开发环境。在生成错误的组件之前。 对于开发环境,项目模板会自动将此中间件注册为管道中的第一个中间件。
诊断提供新应用的开发人员异常页、异常处理、状态代码页和默认网页的几个单独的中间件。在生成错误的组件之前。 异常终端或为新应用提供默认网页的终端。
转接头将代理标头转发到当前请求。在使用已更新字段的组件之前。 示例:方案、主机、客户端 IP、方法。
运行状况检查检查 ASP.NET Core 应用及其依赖项的运行状况,如检查数据库可用性。如果请求与运行状况检查终结点匹配,则为终端。
标头传播将 HTTP 标头从传入的请求传播到传出的 HTTP 客户端请求中。
HTTP日志记录 记录 HTTP 请求和响应。中间件管道的开头。
HTTP方法重写 允许传入 POST 请求重写方法。在使用已更新方法的组件之前。
HTTPS重定向 将所有 HTTP 请求重定向到 HTTPS。在使用 URL 的组件之前。
HTTP严格传输安全性 (HSTS) 添加特殊响应标头的安全增强中间件。在发送响应之前,修改请求的组件之后。 示例:转接头、URL 重写。
MVC用 MVC/Razor Pages 处理请求。如果请求与路由匹配,则为终端。
OWIN与基于 OWIN 的应用、服务器和中间件进行互操作。如果 OWIN 中间件处理完请求,则为终端。
请求解压缩 提供对解压缩请求的支持。 在读取请求正文的组件之前。
响应缓存提供对缓存响应的支持。在需要缓存的组件之前。 UseCORS 必须在 UseResponseCaching 之前。
响应压缩提供对压缩响应的支持。在需要压缩的组件之前。
请求本地化提供本地化支持。在对本地化敏感的组件之前。 使用 RouteDataRequestCultureProvider 时,必须在路由中间件之后显示。
终结点路由定义和约束请求路由。用于匹配路由的终端。
SPA通过返回单页应用程序 (SPA) 的默认页面,在中间件链中处理来自这个点的所有请求 在链中处于靠后位置,因此其他服务于静态文件、MVC 操作等内容的中间件占据优先位置。
会话提供对管理用户会话的支持。在需要会话的组件之前。
静态文件为提供静态文件和目录浏览提供支持。如果请求与文件匹配,则为终端。
URL 重写提供对重写 URL 和重定向请求的支持。在使用 URL 的组件之前。
W3CLogging以 W3C 扩展日志文件格式生成服务器访问日志。中间件管道的开头。
WebSockets启用 WebSockets 协议。在接受 WebSocket 请求所需的组件之前。

更多请参考微软官方文档

以上是关于[netcore] ASP.NET Core 中间件的主要内容,如果未能解决你的问题,请参考以下文章

[netcore] ASP.NET Core 中间件

asp.net core 自定义异常处理中间件

如何在 ASP.Net Core 中使用 条件中间件

ASP.Net Core 异常处理中间件

ASP.NET Core 2.0 身份验证中间件

写入自定义 ASP.NET Core 中间件