问题 中间件应该总是调用下一个?


我一直在努力了解ASP.NET 5管道中间件如何真正起作用。据我所知,中间件只是一个 Func<RequestDelegate, RequestDelegate>,这是一个指向接收对下一个请求委托的引用的方法的指针,并返回一个包装下一个请求委托的新方法。当然,我们可以使用类来表示中间件,例如:

public class MyMiddleware
{
    private readonly _next;

    public MyMiddleware(RequestDelegate next)
    {
        if (next == null)
        {
            throw new ArgumentNullException("next");
        }

        _next = next;
    }

    public Task Invoke(HttpContext context)
    {
        // New request delegate code here which can wrap the next one on the pipeline
    }
}

自从 RequestDelegate 是一个委托,可以保存对接收方法的方法的引用 HttpContext 并返回一个 Task 该 Invoke method是要返回的请求委托,并且可以访问管道上的下一个委托委托。

然后,在编写中间件时,我们可以访问管道的下一个组件,但我有一个疑问。一开始我认为理想总是以下列方式工作:

  • 检查中间件是否可以处理请求
  • 如果可以,做任何必须做的事情 HttpContext
  • 调用管道上的下一个中间件

因此,当我第一次研究这个时,我认为每个中间件应该总是调用下一个。但这样做导致了如上所述的奇怪行为 这个问题

另外看一些中间件的源代码,我看到其中一些中间件遵循另一个步骤:

  • 检查中间件是否可以处理请求
  • 如果可以,做任何必须做的事情 HttpContext 就这样
  • 如果不, 只有不是 打电话给下一个

这是使用中间件的真正想法吗?这方面的正确方法是什么?每个中间件都会执行必须完成的请求,并始终调用下一个或者如果中间件可以处理它不再调用下一个请求的请求?

我相信中间件只有在无法处理请求时才应调用下一个。我认为这是因为如果没有,管道上的中间件之间会有耦合。因此,为了处理请求,中间件需要知道前一个做了什么以避免弄乱一切。这个结论对吗?


6938
2018-03-07 02:48


起源



答案:


存在中间件以使请求管道模块化,这意味着只要您尊重合同,就可以添加/删除/替换部件。例如,如果您的应用程序在没有任何缓存的情况下提供某些文件,则可以在管道前面添加中间件而不更改其余文件。它们是构建块。

中间件可以:

  1. 什么也不做,并进一步传递请求(例如,只适用于POST请求的中间件,但当前的请求是GET)
  2. 没做什么 对请求,做一些别的事情,并进一步传递(例如伐木)
  3. 对请求执行某些操作并进一步传递请求(例如,获取身份验证令牌并将其转换为标识,或从请求中删除一些敏感信息)
  4. 结束管道而不是进一步传递请求(例如 StaticFileMiddleware 只返回文件,或路由匹配时的MVC)

可能回答你的问题 其他问题 也是:有两种类型的中间件:

  1. 旨在做某事并进一步传递数据的中间件(等等身份验证,cookie,验证,日志记录等)
  2. 完成管道的中间件(静态文件,MVC等)。

当然,有些人可能会根据具体情况做两件事。例如,如果凭据不正确,auth可以结束管道,否则继续。

中间件的作者必须决定是否应该调用下一个中间件(如果有的话)。如果您的问题中的中间件返回一条消息,则不应调用下一条消息。


15
2018-03-07 05:39