关于 ASP.NET Core 中的异常处理中间件


顾名思义这个中间件就是提供一个异常处理器来处理抛出的异常,所谓的异常处理器就是一个请求委托对象。
异常处理中间件捕捉到抛出的异常后,会利用它来处理当前的请求。

前言:

本文使用 .NET Core SDK 3.1 的版本
ASP.NET Core 应用在处理某个请求的时候出现了错误,一般会返回状态码为500的响应。由于出于安全的考虑,详细的错误信息都不会跟着响应发放给客户端。
如果我们要去精确地定位到作为错误根源的那一行代码,一个是利用日志,另一种就是直接显现出错误页面。
在 ASP.NET Core 中,系统提供了 开发者异常页面中间件异常处理中间件状态码页面中间件 三种处理处理异常的中间件。

一、开发人员异常中间件

出于安全方面的考虑,为了避免敏感信息的泄露,客户端默认情况下是不会得到详细的错误信息。
但是这让我们在开发过程中增加了查错的难度,尤其在生产环境中。
开发人员异常中间件能够根据具体的错误类型得到具体的针对性的友好的错误消息。
如果使用开发人员异常中间件,会把异常的详细信息和基于当前请求的上下文直接呈现在错误页面中。

    Host.CreateDefaultBuilder()
        .ConfigureWebHostDefaults(builder =>
        {
            builder.Configure(app =>
            {
            	// 发者异常页面中间件,会将异常的详细信息都显示出来
                app.UseDeveloperExceptionPage();
                app.UseRouting();
                app.UseEndpoints(routeBuilder =>
                {
                    routeBuilder.MapGet("/", (HttpContext context) =>
                        Task.FromException(new Exception("This is Exception")));
                });
            });
        })
        .Build()
        .Run();

但是在生产环境下,我们更倾向于为用户呈现一个定制的错误页面,这可以通过注册一个异常处理中间件来实现,

二、异常处理中间件

1) 用ExceptionHandlerOptions对象提供用来处理请求的RequestDelegate

最终体现在提供一个请求处理的委托,来处理抛出的异常并完成最终的响应。

    var options = new ExceptionHandlerOptions
    {
        // ExceptionHandler 是 RequestDelegate 对象
        ExceptionHandler = context => context.Response.WriteAsync("Hello Exception!")
    };
    
    Host.CreateDefaultBuilder()
        .ConfigureWebHostDefaults(builder => builder
            .Configure(app =>
            {
                // 异常处理中间件
                // 这里仅仅将定制的错误消息作为响应内容
                app.UseExceptionHandler(options);
                app.Run(context => Task.FromException(new InvalidOperationException("Throw Exception")));
            }))
        .Build()
        .Run();
2) 直接注册一个中间件处理异常

最终体现在提供一个请求处理的委托,来处理抛出的异常并完成最终的响应。

    static void configure(IApplicationBuilder applicationBuilder) => 
        applicationBuilder.Run(context => context.Response.WriteAsync("Hello Exception!"));
    
    Host.CreateDefaultBuilder()
        .ConfigureWebHostDefaults(builder =>
        {
            builder.Configure(app =>
            {
                app.UseExceptionHandler(configure);
                app.Run(context => Task.FromException(new InvalidOperationException("这是一个异常")));
            });
        })
        .Build()
        .Run();
3) 服务器重定向到异常页面

如果想使用错误页面,并这个错误页面拥有一个固定的路径,那么只需要重定向到这个错误页面指向的路径即可。

    Host.CreateDefaultBuilder()
        .ConfigureWebHostDefaults(builder =>
        {
            builder.Configure(app =>
            {
                app.UseExceptionHandler("/error");
                app.UseRouting();
                app.UseEndpoints(routeBuilder => routeBuilder.MapGet("error", ExceptionPageAsync));
                app.Run(context => Task.FromException(new InvalidOperationException("Throw Exception")));
            });
        })
        .Build()
        .Run();
    
    static Task ExceptionPageAsync(HttpContext context)
    {
        return context.Response.WriteAsync("Hello Exception");
    }

三、状态码页面中间件

由于web应用都是采用 http 通信协议,
我们应该尽可能符合 http 标准,并将协议范围中的语义应用到程序中,这主要体现在http响应状态码上。
http 的错误大体分为两种类型,一种是客户端错误,http状态码是400 ~ 499。还有一种是服务端错误,http状态码是 500 ~ 599
状态码页面中间件被调用的前提是后续请求过程中产生了一个错误的响应状态码。

1) 直接设置响应正文

状态码页面中间件被调用的前提是后续请求过程中产生了一个错误的响应状态码。
作为响应内容的字符串可以包含一个占位符,状态码页面中间件会采用当前的状态码来替换这个占位符。

    Host.CreateDefaultBuilder()
        .ConfigureWebHostDefaults(builder =>
        {
            builder.Configure(app =>
            {
            	// 这里的第一个参数是响应的媒体类型,第二个参数是内容
                app.UseStatusCodePages("text/plain", "Error ({0})");
                app.Run(context => Task.Run(() => context.Response.StatusCode = 500));
            });
        })
        .Build()
        .Run();
2) 指定状态码错误处理器

指定状态码错误处理器可以根据不同的 Http状态码 自定义逻辑。

    Host.CreateDefaultBuilder()
        .ConfigureWebHostDefaults(builder =>
        {
            builder.Configure(app =>
            {
                app.UseStatusCodePages(ExceptionPageAsync);
                app.Run(context => Task.Run(() => context.Response.StatusCode = Random.Next(400, 500)));
            });
        })
        .Build()
        .Run();
    
    static async Task ExceptionPageAsync(StatusCodeContext context)
    {
        var response = context.HttpContext.Response;
    
        if (response.StatusCode < 500)
            await response.WriteAsync($"Client Error ({response.StatusCode})");
        else
            await response.WriteAsync($"Server Error ({response.StatusCode})");
    }
3) 重定向的状态码页面中间件

重定向在 ASP.NET Core 中有两个中间件,一个是客户端重定向,另一个是服务端重定向。

    Host.CreateDefaultBuilder()
        .ConfigureWebHostDefaults(builder =>
        {
            builder.Configure(app =>
            {
                // 具有客户端重定向功能的状态码页面中间件
                app.UseStatusCodePagesWithRedirects("/error/{0}");
    
                // 具有服务器重定向功能的状态码页面中间件
                // app.UseStatusCodePagesWithReExecute("/error/{0}");
    
                app.UseRouting();
                app.UseEndpoints(routeBuilder => routeBuilder.MapGet("error/{status_code}", HandlerError));
                app.Run(context => Task.Run(() => context.Response.StatusCode = Random.Next(400, 599)));
            });
        })
        .Build()
        .Run();
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值