假设我们有以下代码:
public class MiddleWareFirst
{
private RequestDelegate next;
public MiddleWareFirst(RequestDelegate nextDelegate) {
next = nextDelegate;
}
public async Task Invoke(HttpContext context) {
await context.Response.WriteAsync("Start n");
if (next != null) {
await next(context);
}
}
}
public class MiddleWareSecond
{
private RequestDelegate next;
public MiddleWareSecond(RequestDelegate nextDelegate) {
next = nextDelegate;
}
public async Task Invoke(HttpContext context) {
if (next != null) {
await next(context); // <---- should throw the exception caused by MiddleWareThird
}
}
}
public class MiddleWareThird
{
private RequestDelegate next;
public MiddleWareThird(RequestDelegate nextDelegate) {
next = nextDelegate;
}
public async Task Invoke(HttpContext context) {
throw new System.Exception();
}
}
并将管道构建为:
// Configure method in startup.cs
app.UseMiddleware<MiddleWareFirst>();
app.UseMiddleware<MiddleWareSecond>();
app.UseMiddleware<MiddleWareThird>();
您可以看到MiddleWareThird
抛出异常。当我运行应用程序时,我可以看到网页的输出是";"开始";,这让我很困惑,难道不是500的错误吗?
因为我们知道await
可以抛出任务的异常。因此,对于MiddleWareSecond
,由于它不使用try-catch块来捕获异常,因此返回到MiddleWareFirst
的任务应该在内部包含异常。由于MiddleWareFirst
也不使用try-catch块,因此异常将传播到web服务器,该服务器应生成500错误页面。但是输出是正常的,那么MiddleWareThird
中抛出的异常是如何神奇地被吞噬的呢?
异常将传播到web服务器,该服务器应生成500个错误页面的
由于您已经开始使用await context.Response.WriteAsync("Start n");
进行响应,因此根据HTTP协议将200
写入响应流,您在第一行中发送状态。
如果在WriteAsync
之前将抛出异常,那么您将按照预期从服务器获得500
。
这是由aspnet core
基础设施处理的,在日志中您可能会注意到异常已被记录。
当然,您可以使用自定义中间件来处理DeveloperExceptionPageMiddleware
之类的异常
public async Task Invoke(HttpContext context)
{
try
{
await _next(context);
}
catch (Exception ex)
{
//...
}
}
https://github.com/dotnet/aspnetcore/blob/f74c6f12d868b8e5c91e85f1a2bcbd1134ed5fd5/src/Middleware/Diagnostics/src/DeveloperExceptionPage/DeveloperExceptionPageMiddleware.cs#L90-L127