[英]why writing to HttpContext.Response "short-circuit" MVC pipeline
下面是代码:
public class Startup
{
// ...
public void Configure(IApplicationBuilder app)
{
app.UseRouting();
app.Use(async (context, next) =>
{
await context.Response.WriteAsync("write sth first\n");
await next();
});
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
我只得到“先写”响应,控制器的动作方法生成的内容没有附加到响应中。 但是,我在控制器的 action 方法上放了一个调试器,调试器正在命中,这意味着 MVC 管道仍在运行(这并不是真正的短路)那么为什么来自 action 方法的响应不在响应中?
更让我困惑的是,如果我将代码更改为:
public class Startup
{
// ...
public void Configure(IApplicationBuilder app)
{
app.UseRouting();
app.Use(async (context, next) =>
{
await context.Response.WriteAsync("write sth first\n");
await next();
});
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/", async context => {
await context.Response.WriteAsync("Hello World!");
});
});
}
}
然后我得到一个响应是“先写东西\n“Hello World!”,那么为什么这次来自端点的响应被附加到响应中?
endpoints.MapControllers()
中是否有任何检查HttpContext.Response
的地方,比如是否有内容然后中止剩余的进程? 这部分的源代码在哪里?
这是我尝试时的错误
System.InvalidOperationException: Headers are read-only, response has already started.
所以它与中间件或 MVC 管道无关。 控制器需要编写 HTTP 标头,但它不能,因为响应已经开始。
鉴于其他中间件可能也需要写入Response
,您不应该自己开始写入。 您可以尝试附加到OnStarting
事件。 这样你就不会自己启动响应(内存中的伪代码):
app.Use(async (context, next) =>
{
context.Response.OnStarting(async () =>
{
await context.Response.WriteAsync("write sth first\n");
});
await next();
}
为什么这次来自端点的响应被附加到响应中
那是因为端点中间件是在您的自定义中间件之后调用的。 因此,它首先调用您的中间件,然后调用端点中间件。 中间件顺序很重要。
根据 tia 的回答,我尝试替换默认的响应正文,并且 Response.HasStarted 属性为 false,您可以看到页面以开始时间和结束时间呈现,context.Response.WriteAsync 不会使管道短路:
app.Use(async (context, next) =>
{
var response = context.Response;
var responseOriginalBody = response.Body;
using var memStream = new MemoryStream();
response.Body = memStream;
await context.Response.WriteAsync(string.Format("<a>starttime:{0}</a>", DateTime.Now.ToString("yyyy/MM/dd/HH:mm:ss.fff")));
var start = context.Response.HasStarted;
await next.Invoke();
await context.Response.WriteAsync(string.Format("<a>endtime:{0}</a>", DateTime.UtcNow.ToString("yyyy/MM/dd/HH:mm:ss.fff")));
memStream.Position = 0;
await memStream.CopyToAsync(responseOriginalBody);
response.Body = responseOriginalBody;
});
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.