为什么404中间件的行为如此?

use*_*696 7 c# owin asp.net-core

看一下ASP.NET 5的源代码,我在HTTP抽象中发现了具体的实现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;
}
Run Code Online (Sandbox Code Playgroud)

我明白了:我们编写请求委托返回404的代码,这样如果没有中间件处理请求,我们就会返回404错误.现在,假设我们编写以下中间件(它只是一个Func<RequestDelegate, RequestDelegate>):

(next) => {
    RequestDelegate reqDelegate = new RequestDelegate(async context => {
        await context.Response.WriteAsync("Hello World!");
        await next.Invoke(context);
    });

    return reqDelegate;
} 
Run Code Online (Sandbox Code Playgroud)

也就是说,它返回一个"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,结果如下:

  • 使用IIS express时,不会调用中间件.如果我们遇到一个未知的端点,那么处理的IIS就会被忽略.
  • 使用WebListener时,中间件确实被调用了.

但是,有一个奇怪的问题:在我的设置中,我有一个helloWorld中间件和一个howAreYou中间件.这howAreYou是管道的最后一部分,接下来就是404.当我将404链接在一起并调用它时,我在Fiddler上调试时返回错误504并显示消息

[Fiddler] ReadResponse()失败:服务器没有为此请求返回完整的响应.服务器返回158个字节.

在VS上调试似乎每个中间件被调用两次.我不知道它是否是一个bug,如果它是特定于WebListener的,但我真的不知道它是如何工作的.

这是否意味着在处理请求时我不应该调用管道上的下一个中间件?但是,如果我想打电话给下一个怎么办?