查看ASP.NET 5的源代码,我在HTTP abstractions上找到了IApplicationBuilder
的具体实现。该类有一个方法,负责从添加的中间件中构建管道。代码如下:
public RequestDelegate Build()
{
RequestDelegate app = context =>
{
context.Response.StatusCode = 404;
return Task.FromResult(0);
};
foreach (var component in _components.Reverse())
{
app = component(app);
}
return app;
}
我明白了:我们编写请求委托返回404的代码,这样如果没有中间件处理请求,我们就会返回404错误。现在,假设我们编写以下中间件(只是Func<RequestDelegate, RequestDelegate>
):
(next) => {
RequestDelegate reqDelegate = new RequestDelegate(async context => {
await context.Response.WriteAsync("Hello World!");
await next.Invoke(context);
});
return reqDelegate;
}
这就是它返回一个“Hello World”消息,并调用管道上添加的下一个功能,无论是什么。现在,如果我们只是在Use
上添加Configure
调用,则会在我们请求任何内容时在屏幕上显示“Hello World”。
但是等一下:404错误中间件正在被添加到管道中,作为该管道的下一个。在这种情况下,next.Invoke(context)
应该只返回404.但它不会,也就是说,它显示状态代码为200的“Hello World”。
我已经尝试过编写这样的另一个中间件并添加到管道中并且两者都被调用,但404没有。我在这里缺少什么?为什么404没有被调用,因为他是管道的最后一个中间件的下一个?
编辑:做一些测试我发现了一些有趣的东西。我已经更改了这个hello world中间件,只要请求的路径为/helloworld
,它就会在响应流上写入。在那种情况下,当我们请求http://localhost:5000/helloworld
时,我们会收到hello world消息,并且不会调用404中间件。
另一方面,如果我们请求任何其他路径,例如http://localhost:5000/test
,它会忽略helloworld(如预期的那样)并返回404.
在这种情况下,如果管道上的中间件没有对请求/响应做任何事情,似乎只使用了404。那是真的吗?如果是这样,那么执行此操作的代码在哪里?
编辑2:我已尝试使用ASP.NET源代码本身进行更多测试。我在本地克隆了HTTP抽象存储库并添加到global.json
内的“源”中,这允许我调试源代码。我在代理处添加了一个断点,返回404,结果如下:
但是,有一个奇怪的问题:在我的设置中,我有一个helloWorld
中间件和一个howAreYou
中间件。 howAreYou
是管道的最后一部分,它的 next 是404.当我将404链接在一起并调用它时,我在Fiddler上调试时返回错误504并显示消息
[Fiddler] ReadResponse()失败:服务器未返回此请求的完整响应。服务器返回158个字节。
在VS上调试似乎每个中间件被调用两次。我不知道它是否是一个bug,如果它是特定于WebListener的,但我真的不知道它是如何工作的。
这是否意味着在处理请求时我不应该调用管道上的下一个中间件?但是,如果我想打电话给下一个呢?