ASP.NET 核心 2.1 中间件返回 404



我决定为 ASP.NET API 核心 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; }
} 

当我尝试在我的应用程序中使用此中间件时.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();
}

这工作得很好,但是当我从MapMiddlewareGet中删除appBuilder.UseMvc((和我的函数调用返回404的特定路由时。

我试图将appRouter放在app.useMvc((之上。没有成功,我的中间件下一个函数在_next时仍然返回 404。调用了 Invoke((。

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

您的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. 如果不是,则表示此处的路由器不匹配,并且将不执行任何操作,然后将请求分派给下一个中间件。

最新更新