一个中间件应该总是调用下一个?
A middleware should always invoke the next?
我一直在努力了解 ASP.NET 5 个管道中间件的真正工作原理。据我所知,中间件只是一个 Func<RequestDelegate, RequestDelegate>
,它是一个指向接收对下一个请求委托的引用的方法的指针,returns 是一个包装下一个请求委托的新方法。我们当然可以使用 class 来表示中间件,例如:
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
和 returns 一个 Task
方法的引用,因此 Invoke
方法是请求返回委托并且可以访问管道中的下一个委托。
然后,在编写中间件代码时,我们可以访问管道的下一个组件,但我有疑问。一开始我认为理想的工作方式总是如下:
- 检查中间件是否可以处理请求
- 如果可以,用
HttpContext
做任何必须做的事
- 调用管道上的下一个中间件
所以当我第一次研究这个时,我认为每个中间件应该总是调用下一个。但是这样做会导致 this question.
上讨论的奇怪行为
我还查看了一些中间件的源代码,我发现其中一些遵循了其他步骤:
- 检查中间件是否可以处理请求
- 如果可以,用
HttpContext
做任何必须做的事情,仅此而已
- 如果没有,并且仅当没有调用下一个
这就是使用中间件的真正想法吗?哪种方法是正确的方法?每个中间件执行必须对请求完成的操作并始终调用下一个,或者如果中间件可以处理请求它不再调用下一个?
我认为中间件只有在无法处理请求时才应调用下一个。我认为那是因为如果不这样做,管道上的中间件之间就会耦合。因此,为了处理请求,中间件需要知道前一个中间件做了什么以避免弄乱一切。这个结论对吗?
中间件的存在是为了使请求管道模块化,这意味着只要您遵守合同,您就可以从中 add/remove/replace 部分。例如,如果您的应用程序提供一些没有任何缓存的文件,您可以在管道的前端添加一个中间件而不改变其余部分。它们是积木。
中间件可以:
- 不做任何事情并进一步传递请求(例如,仅适用于 POST 请求但当前请求为 GET 的中间件)
- 不对请求执行任何操作,而是执行其他操作并进一步传递它(例如日志记录)
- 对请求做一些事情并进一步传递请求(例如获取身份验证令牌并将其转换为身份,或从请求中删除一些敏感信息)
- 结束管道并且不进一步传递请求(例如 StaticFileMiddleware 只是 returns 文件,或者路由匹配时的 MVC)
可能也会回答您的 other question:有两种类型的中间件:
- 旨在做某事并进一步传递数据的中间件(例如身份验证、cookie、验证、日志记录等)
- 完成管道的中间件(静态文件、MVC 等)。
当然,有些人可能会根据上下文同时执行这两种操作。例如,如果凭据不正确,auth 可以结束管道,否则继续。
中间件的作者必须决定是否调用下一个中间件(如果有的话)。对于您问题中的中间件 returns 一条消息,它不应调用下一条消息。
我一直在努力了解 ASP.NET 5 个管道中间件的真正工作原理。据我所知,中间件只是一个 Func<RequestDelegate, RequestDelegate>
,它是一个指向接收对下一个请求委托的引用的方法的指针,returns 是一个包装下一个请求委托的新方法。我们当然可以使用 class 来表示中间件,例如:
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
和 returns 一个 Task
方法的引用,因此 Invoke
方法是请求返回委托并且可以访问管道中的下一个委托。
然后,在编写中间件代码时,我们可以访问管道的下一个组件,但我有疑问。一开始我认为理想的工作方式总是如下:
- 检查中间件是否可以处理请求
- 如果可以,用
HttpContext
做任何必须做的事
- 调用管道上的下一个中间件
所以当我第一次研究这个时,我认为每个中间件应该总是调用下一个。但是这样做会导致 this question.
上讨论的奇怪行为我还查看了一些中间件的源代码,我发现其中一些遵循了其他步骤:
- 检查中间件是否可以处理请求
- 如果可以,用
HttpContext
做任何必须做的事情,仅此而已 - 如果没有,并且仅当没有调用下一个
这就是使用中间件的真正想法吗?哪种方法是正确的方法?每个中间件执行必须对请求完成的操作并始终调用下一个,或者如果中间件可以处理请求它不再调用下一个?
我认为中间件只有在无法处理请求时才应调用下一个。我认为那是因为如果不这样做,管道上的中间件之间就会耦合。因此,为了处理请求,中间件需要知道前一个中间件做了什么以避免弄乱一切。这个结论对吗?
中间件的存在是为了使请求管道模块化,这意味着只要您遵守合同,您就可以从中 add/remove/replace 部分。例如,如果您的应用程序提供一些没有任何缓存的文件,您可以在管道的前端添加一个中间件而不改变其余部分。它们是积木。
中间件可以:
- 不做任何事情并进一步传递请求(例如,仅适用于 POST 请求但当前请求为 GET 的中间件)
- 不对请求执行任何操作,而是执行其他操作并进一步传递它(例如日志记录)
- 对请求做一些事情并进一步传递请求(例如获取身份验证令牌并将其转换为身份,或从请求中删除一些敏感信息)
- 结束管道并且不进一步传递请求(例如 StaticFileMiddleware 只是 returns 文件,或者路由匹配时的 MVC)
可能也会回答您的 other question:有两种类型的中间件:
- 旨在做某事并进一步传递数据的中间件(例如身份验证、cookie、验证、日志记录等)
- 完成管道的中间件(静态文件、MVC 等)。
当然,有些人可能会根据上下文同时执行这两种操作。例如,如果凭据不正确,auth 可以结束管道,否则继续。
中间件的作者必须决定是否调用下一个中间件(如果有的话)。对于您问题中的中间件 returns 一条消息,它不应调用下一条消息。