【问题标题】:ASP.NET Core 2.1 Middleware returns 404ASP.NET Core 2.1 中间件返回 404
【发布时间】:2019-03-08 19:09:10
【问题描述】:

我决定为 ASP.NET API core 2.1 制作一个自定义中间件。

public class AuthorizeMiddleware
{
    private readonly RequestDelegate _next;
    private readonly AuthorizeOptions _options;

    public AuthorizeMiddleware(RequestDelegate next, AuthorizeOptions options)
    {
        _next = next;
        _options = options;
    }


    public async Task Invoke(HttpContext context)
    {
        bool hasRole = false;
        if (hasRole)
        {
            await context.Response.WriteAsync($"Not authorized, you need role: {_options.Role}");
        }
        else
        {
            await _next.Invoke(context);
        }

    }

}        
public struct AuthorizeOptions
{
    public AuthorizeOptions(string role)
    {
        Role = role;
    }
    public string Role { get; set; }
} 

当我尝试在我的 Application.cs 中使用这个中间件时

 public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {

        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseHsts();
            app.UseHttpsRedirection();
        }

        app.UseRouter(AuthenticatedRoutes(app));

        app.UseMvc();
    }

    private IRouter AuthenticatedRoutes(IApplicationBuilder applicationBuilder)
    {

        IRouteBuilder builder = new RouteBuilder(applicationBuilder);

        builder.MapMiddlewareGet("/api/values", appBuilder =>
        {
            appBuilder.UseMiddleware<AuthorizeMiddleware>(new AuthorizeOptions("User"));
            appBuilder.UseMvc();
        });

        return builder.Build();
    }

这工作得很好,但是当我删除 appBuilder.UseMvc();从 MapMiddlewareGet 和我的函数调用返回 404 的具体路线。

我尝试将 appRouter 放在 app.useMvc() 之上。如果没有成功,当调用 _next.Invoke() 时,我的中间件 next 函数仍然返回 404。

那么为什么每当我在 appBuilder 中调用 useMvc() 时它会起作用,我是否在做一些被认为是不好的做法,为什么我必须在 MapMiddlewareGet() 中使用 app.useMvc()?

【问题讨论】:

标签: asp.net-core-webapi asp.net-core-2.1 asp.net-core-middleware


【解决方案1】:

您的AuthenticatedRoutes() 尝试做的是使用中间件构建路由器,因此我们可以使用最终返回的 IRouter 作为RouterMiddleware 来处理请求。 但是,一旦已经有匹配的处理程序,RouterMiddleware 将永远不会继续路由。因此,它不会自动将请求从一个RouterMiddlware“分派”到另一个RouterMiddleware

让我们检查您的代码:

app.UseRouter(AuthenticatedRoutes(app));

如您所知,这里的方法app.UseRouter() 是一个扩展方法,它只是使用RouterMiddlware。所以第一个问题是:路由器中间件是如何工作的?让我们看一下源代码:

public class RouterMiddleware
{
    private readonly IRouter _router;

    // ...

    public async Task Invoke(HttpContext httpContext)
    {
        var context = new RouteContext(httpContext);
        context.RouteData.Routers.Add(_router);
        await _router.RouteAsync(context);
        if (context.Handler == null){
            _logger.RequestDidNotMatchRoutes();
            await _next.Invoke(httpContext);
        } else {
            httpContext.Features[typeof(IRoutingFeature)] = new RoutingFeature(){
                RouteData = context.RouteData,
            };
            await context.Handler(context.HttpContext);
        }
    }
}

正如您在此处看到的,RouterMiddleware 针对上下文进行路由并检查是否有匹配的RouterHandler

  1. 如果没有,什么都不做,然后将请求分派到下一个中​​间件
  2. 否则,使用RouterHandler 处理请求。 请注意,它永远不会将请求分派给下一个中间件

让我们回顾一下您的路由器和RouterHandler 的工作原理:

private IRouter AuthenticatedRoutes(IApplicationBuilder applicationBuilder)
{

    IRouteBuilder builder = new RouteBuilder(applicationBuilder);

    builder.MapMiddlewareGet("/api/values", appBuilder =>
    {
        appBuilder.UseMiddleware<AuthorizeMiddleware>(new AuthorizeOptions("User"));
        appBuilder.UseMvc();
    });

    return builder.Build();
}

看到了吗?您的路由将检查 HTTP 方法是否为 HttpGet 以及 url 是否可以匹配 /api/values

  1. 如果是,则表示路由匹配,会调用特定的RouterHandler处理请求。

    • RouterHandler会首先调用AuthorizeMiddleware的中间件
    • 如果添加appBuilder.UseMvc();,它将调用匹配的操作
    • 如果没有appBuilder.UseMvc();,它将终止进一步的进程,并最终产生404 响应。
  2. 如果不匹配,说明这里的路由器不匹配,什么都不做,然后将请求分派给下一个中间件。

【讨论】:

    猜你喜欢
    • 2021-07-13
    • 2020-03-24
    • 2018-11-28
    • 2019-08-16
    • 2021-02-01
    • 2019-03-21
    • 1970-01-01
    • 1970-01-01
    • 2021-03-13
    相关资源
    最近更新 更多