.NET8入门:6.中间件

ASP.NET Core中的中间件(Middleware)是指位于客户端和服务器之间的软件。在应用管道中处理请求和响应,可以选择是否将请求传递到管道的下一个中间件中,也可以配置其在某个中间件前后执行。

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

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

中间件管道

ASP.NET Core中的请求管道包含了一系列的请求委托,依次调用。如图:

Run委托

Run委托中不能执行next,可以直接让请求管道短路(直接终止管道)。详情请见代码示例:

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

app.Run(async context => { await context.Response.WriteAsync("Hello World!"); });

//Hello End将不会打印,因为Run委托使管道短路了
app.Run(async context => { await context.Response.WriteAsync("Hello End!"); });

app.Run();

如果需要管道中执行下一个委托的话,需要使用Use。详情请见代码示例:

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

app.Use(async (context, next) =>
{
    await context.Response.WriteAsync("Hello World!");
    await next.Invoke();
});

//Hello End打印
app.Run(async context => { await context.Response.WriteAsync("Hello End!"); });

app.Run();

中间件顺序

ASP.NET Core中的中间件的自定义执行应顺序如下图所示:

如果未调用Routing,则Routing在请求管道开始时运行。

管道分支

ASP.NET Core通过使用Map、MapWhen和UseWhen关键字对管道进行分支处理。

        1.Map

Map会根据请求路径来进行分支匹配,如果请求路径以给定路径开头,则命中分支,参考代码如下:

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

app.Map("/map1", HandleMapTest1);

app.Map("/map2", HandleMapTest2);

app.Run(async context =>
{
    await context.Response.WriteAsync("Hello from non-Map delegate.");
});

app.Run();

static void HandleMapTest1(IApplicationBuilder app)
{
    app.Run(async context =>
    {
        await context.Response.WriteAsync("Map Test 1");
    });
}

static void HandleMapTest2(IApplicationBuilder app)
{
    app.Run(async context =>
    {
        await context.Response.WriteAsync("Map Test 2");
    });
}

请求响应结果如下:

请求

响应

localhost:1234

Hello from non-Map delegate.

localhost:1234/map1

Map Test 1

localhost:1234/map2

Map Test 2

localhost:1234/map3

Hello from non-Map delegate.

        2.MapWhen

MapWhen可以使用条件判断来命中管道分支,参考代码如下:

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

app.MapWhen(context => context.Request.Query.ContainsKey("branch"), HandleBranch);

app.Run(async context =>
{
    await context.Response.WriteAsync("Hello from non-Map delegate.");
});

app.Run();

static void HandleBranch(IApplicationBuilder app)
{
    app.Run(async context =>
    {
        var branchVer = context.Request.Query["branch"];
        await context.Response.WriteAsync($"Branch used = {branchVer}");
    });
}

请求响应结果如下:

请求

响应

localhost:1234

Hello from non-Map delegate.

localhost:1234/?branch=main

Branch used = main

        3.UseWhen

UseWhen效果等同于MapWhen,但是如果分支不包含短路或者终端中间件,将会在执行完管道分支之后重新加入主管道,参考代码如下:

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

app.UseWhen(context => context.Request.Query.ContainsKey("branch"),
    appBuilder => HandleBranchAndRejoin(appBuilder));

app.Run(async context =>
{
    await context.Response.WriteAsync("Hello from non-Map delegate.");
});

app.Run();

void HandleBranchAndRejoin(IApplicationBuilder app)
{
    var logger = app.ApplicationServices.GetRequiredService<ILogger<Program>>(); 

    app.Use(async (context, next) =>
    {
        var branchVer = context.Request.Query["branch"];
        logger.LogInformation("Branch used = {branchVer}", branchVer);

        // Do work that doesn't write to the Response.
        await next();
        // Do other work that doesn't write to the Response.
    });
}

自定义中间件

ASP.NET Core中,自定中间件步骤如下:

        1.声明使用约定激活的中间件

public class ConventionalMiddleware
{
    private readonly RequestDelegate _next;

    public ConventionalMiddleware(RequestDelegate next)
        => _next = next;

    public async Task InvokeAsync(HttpContext context, SampleDbContext dbContext)
    {
        var keyValue = context.Request.Query["key"];

        if (!string.IsNullOrWhiteSpace(keyValue))
        {
           await context.Response.WriteAsync($"Output: key—{keyValue}");
        }

        await _next(context);
    }
}

        2.声明使用 MiddlewareFactory 激活的中间件(必须继承自IMiddleware)

public class FactoryActivatedMiddleware : IMiddleware
{

    public FactoryActivatedMiddleware(SampleDbContext dbContext)
        => _dbContext = dbContext;

    public async Task InvokeAsync(HttpContext context, RequestDelegate next)
    {
        var keyValue = context.Request.Query["key"];

        if (!string.IsNullOrWhiteSpace(keyValue))
        {
             await context.Response.WriteAsync($"Output: key—{keyValue}");

        }

        await next(context);
    }
}

        3.为中间件添加扩展

public static class MiddlewareExtensions
{
    public static IApplicationBuilder UseConventionalMiddleware(
        this IApplicationBuilder app)
        => app.UseMiddleware<ConventionalMiddleware>();

    public static IApplicationBuilder UseFactoryActivatedMiddleware(
        this IApplicationBuilder app)
        => app.UseMiddleware<FactoryActivatedMiddleware>();
}

        4.在启动类中进行注册

using Middleware;

var builder = WebApplication.CreateBuilder(args);
//使用 MiddlewareFactory 激活的中间件需要在此注入
builder.Services.AddTransient<FactoryActivatedMiddleware>();

var app = builder.Build();



app.UseConventionalMiddleware();
app.UseFactoryActivatedMiddleware();

app.Run();

        5.在url中加入key参数查看结果

内置中间件

ASP.NET Core中常用内置中间件如下:

中间件

描述

顺序

身份验证

提供身份验证支持。

在需要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 中间件处理完请求,则为终端。

输出缓存

基于配置提供对缓存响应的支持。

在需要缓存的组件之前。UseRouting必须在UseOutputCaching之前。UseCORS必须在UseOutputCaching之前。

响应缓存

提供对缓存响应的支持。 这需要客户端参与才能正常工作。 使用输出缓存实现完整的服务器控制。

在需要缓存的组件之前。UseCORS必须在UseResponseCaching之前。 通过对 Razor Pages 等 UI 应用没有好处,因为浏览器通常会设置阻止缓存的请求头。输出缓存有利于 UI 应用。

请求解压缩

提供对解压缩请求的支持。

在读取请求正文的组件之前。

响应压缩

提供对压缩响应的支持。

在需要压缩的组件之前。

请求本地化

提供本地化支持。

在对本地化敏感的组件之前。 使用RouteDataRequestCultureProvider时,必须在路由中间件之后显示。

请求超时

支持配置请求超时、全局和每个终结点。

UseRequestTimeouts必须在UseExceptionHandler、UseDeveloperExceptionPage和UseRouting后。

终结点路由

定义和约束请求路由。

用于匹配路由的终端。

SPA

通过返回单页应用程序 (SPA) 的默认页面,在中间件链中处理来自这个点的所有请求

在链中处于靠后位置,因此其他服务于静态文件、MVC 操作等内容的中间件占据优先位置。

会话

提供对管理用户会话的支持。

在需要会话的组件之前。

静态文件

为提供静态文件和目录浏览提供支持。

如果请求与文件匹配,则为终端。

URL 重写

提供对重写 URL 和重定向请求的支持。

在使用 URL 的组件之前。

W3CLogging

W3C 扩展日志文件格式生成服务器访问日志。

中间件管道的开头。

WebSockets

启用 WebSockets 协议。

在接受 WebSocket 请求所需的组件之前。

  • 20
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值