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

15

我一直在尝试理解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方法是要返回的请求委托,并且可以访问管道中的下一个委托。

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

  • 检查中间件是否能够处理请求
  • 如果可以,请执行必须在HttpContext中执行的操作
  • 调用管道上的下一个中间件

因此,当我第一次学习这个东西时,我认为每个中间件应该始终调用下一个中间件。但是这样做会导致奇怪的行为,如此问题所述。

此外,查看一些中间件的源代码,我发现其中一些遵循另一些步骤:

  • 检查中间件是否能够处理请求
  • 如果可以,请执行必须在HttpContext中执行的操作
  • 否则,只有在无法处理时才调用下一个中间件

这是使用中间件的真正思路吗?哪种方式是正确的?每个中间件都对请求执行必须的操作并始终调用下一个中间件,还是如果中间件可以处理请求,则不再调用下一个中间件?

我认为中间件应该只有在无法处理请求时才调用下一个中间件。我之所以这样认为是因为如果不这样做,就会在管道上产生耦合。因此,为了处理请求,中间件需要知道前一个中间件所做的内容以避免出现问题。这个结论正确吗?

1个回答

22

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

一个中间件可以:

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

可能也回答了您的other question:有两种类型的中间件:

  1. 中间件旨在完成某些操作并将数据传递给下一个中间件(例如身份验证、cookies、验证、日志记录等)。
  2. 中间件完成管道的工作(静态文件、MVC等)。

当然,有些中间件可能根据上下文同时完成两者。例如,如果凭据不正确,身份验证可以结束管道,否则可以继续。

中间件的作者必须决定是否调用下一个中间件(如果有)。对于您提出问题的中间件返回消息的情况,它不应调用下一个中间件。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接