中间件如何自动处理下面的中间件抛出的异常



假设我们有以下代码:

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

最新更新