响应管道

Response pipeline

我在使用 Asp.net core 1.0 RTM 时遇到了困难。例如,在下面的情况下,我们将看到输出结果为 "-Message_1--Message_5-":

 public class MessageMiddleware
{
    private readonly RequestDelegate _next;
    private readonly IApplicationBuilder _app;

    public MessageMiddleware(RequestDelegate next, IApplicationBuilder app)
    {
        _next = next;
        _app = app;
    }

    public async Task Invoke(HttpContext context)
    {
        var started1 = context.Response.HasStarted;//false
        await context.Response.WriteAsync("-Message_1-");
        var test = true; // will hit this line
        var started2 = context.Response.HasStarted;//true
        await context.Response.WriteAsync("-Message_5-");

        await _next.Invoke(context);
    }
}

但是在这种情况下(添加了header "Content-Type")结果将只是“-Message_1-”并且执行真的停止了:

  public class MessageMiddleware
{
    private readonly RequestDelegate _next;
    private readonly IApplicationBuilder _app;

    public MessageMiddleware(RequestDelegate next, IApplicationBuilder app)
    {
        _next = next;
        _app = app;
    }

    public async Task Invoke(HttpContext context)
    {
        var started1 = context.Response.HasStarted;//false
        await context.Response.WriteAsync("-Message_1-");
        var started2 = context.Response.HasStarted;//true
        context.Response.ContentType = "text/html";
        var test = true; // will NOT hit this line
        var started3 = context.Response.HasStarted;//will NOT hit this line
        await context.Response.WriteAsync("-Message_5-"); //will NOT hit this line

        await _next.Invoke(context);
    }
}

我在官方文档中只找到了这句话:

Avoid modifying HttpResponse after invoking next, one of the next components in the pipeline may have written to the response, causing it to be sent to the client.

这个问题在 SO:

但是了解在中间件管道期间与 HttpContext.Response 的道具的交互以及这种交互如何影响最终结果是不够的 - HttpResponse 的 headers 和 body 内容。

有人body 可以解释 ASP.NET 内核处理响应的一般行为吗?例如,当响应 headers 被发送到客户端时,设置 HttpContext.Response 属性(headers,body 内容)对此有何影响? 中间件内部(外部)管道何时终止?

谢谢!

作为一般规则,当客户端向服务器发出请求时,它会得到响应。该响应包含 header 和一个 body。 headers 包含许多有关响应的信息,如内容类型、使用的 encoding/compression、cookie 等。这是 [=32] 发回的 headers 的示例=] 在 chrome 开发者工具中看到的站点:

响应的另一部分是 body。它通常包含 html 或 json。这是相同响应的 body 的屏幕截图:

最简单的思考方式是将这两个一起发送给客户端,首先是 header,然后是 body。因此,作为开发人员,您在影响 header 的响应 object 上设置任何值的唯一机会是在您开始发送 body 之前。如果您开始发送响应的 body,您将无法再更改 header,因为它们是在 body 开始发送之前作为响应的第一部分发送的。

这就是为什么@tseng 说 "Don't set headers after you have written something to the response stream"。

如果开发人员不熟悉 http headers,他们可能不会意识到 context.Response.ContentType = "text/html" 正在更改 header,但在幕后,这正是它正在做的.同样,设置 cookie 会在后台更改响应 header。一般而言,如果您要更改响应 object 的某些 属性,您应该问问自己 "will this change an http header?",如果答案是 "yes",那么您需要在做致电 Response.WriteAsync.