每个组件:

  • 选择是否将请求传递到管道中的下一个组件。
  • 可在管道中的下一个组件前后执行工作。

请求委托处理每个 HTTP 请求。

当中间件短路时,它被称为“终端中间件”,因为它阻止中间件进一步处理请求。

将 HTTP 处理程序和模块迁移到 ASP.NET Core 中间件介绍了 ASP.NET Core 和 ASP.NET 4.x 中请求管道之间的差异,并提供了更多的中间件示例。

中间件顺序

 

 

 ASP.NET Core 中间件 自定义全局异常中间件以及 MVC异常过滤器作用

 

 

 此顺序对于安全性、性能和功能至关重要。

 // 运行时调用此方法。使用此方法配置HTTP请求管道。
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            // 启用swagger中间件
            app.UseSwaggerMiddleware();

            // 全局异常捕获
            app.UseErrorHandlingMiddleware();

            //静态文件
            app.UseUploadConfig();

            // 路由中间件
            app.UseRouting();

            // 跨域检查
            app.UseCors(_allowSpecificOrigins);

            // 启用多租户中间件(自定义)
            app.UseMultiTenant();

            // (认证中间件)启用Authentication中间件,遍历策略中的身份验证方案获取多张证件,最后合并放入HttpContext.User中
            app.UseAuthentication();

            // (授权中间件)对请求进行权限验证
            app.UseAuthorization();

           

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
                //endpoints.MapControllerRoute("default", "{__tenant__=tenant1}/api/{controller=Home}/{action=Index}/{id?}");
                //endpoints.MapControllerRoute("default", "{__tenant__=}/api/{controller=Home}/{action=Index}");
            });
        }

在上述代码中:

  • 单个用户帐户创建新的 Web 应用时未添加的中间件已被注释掉。
  • 例如:
    • UseCorsUseAuthentication 和 UseAuthorization 必须按照上述顺序运行。
    • 此错误,UseCors 当前必须在 UseResponseCaching 之前运行。

以下 Startup.Configure 方法将为常见应用方案添加中间件组件:

  1. 异常/错误处理
    • 当应用在开发环境中运行时:
      • UseDeveloperExceptionPage) 报告应用运行时错误。
      • 数据库错误页中间件报告数据库运行时错误。
    • 当应用在生产环境中运行时:
      • UseExceptionHandler) 捕获以下中间件中引发的异常。
      • UseHsts) 添加 Strict-Transport-Security 标头。
  2. UseHttpsRedirection) 将 HTTP 请求重定向到 HTTPS。
  3. UseStaticFiles) 返回静态文件,并简化进一步请求处理。
  4. UseCookiePolicy) 使应用符合欧盟一般数据保护条例 (GDPR) 规定。
  5. UseRouting)。
  6. UseAuthentication) 尝试对用户进行身份验证,然后才会允许用户访问安全资源。
  7. UseAuthorization)。
  8. 如果应用使用会话状态,请在 Cookie 策略中间件之后和 MVC 中间件之前调用会话中间件。
  9. UseEndpoints)。

内置中间件

使用 IApplicationBuilder 创建中间件管道部分。

 

 

 自定义中间件  比如异常中间件

首先,创建一个中间件ExceptionMiddleware

using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace NetLock.Presentation.Api.Middleware
{
    public class ErrorHandlingMiddleware
    {
        private readonly RequestDelegate next;

        private readonly ILogger<ErrorHandlingMiddleware> _logger;
        public ErrorHandlingMiddleware(RequestDelegate next, ILogger<ErrorHandlingMiddleware> logger)
        {
            this.next = next;
            this._logger = logger;
        }
        public async Task InvokeAsync(HttpContext context)
        {
            try
            {
                await next(context);
            }
            catch (Exception ex)
            {
                await HandleExceptionAsync(context, ex);
            }

        }


        private Task HandleExceptionAsync(HttpContext context, Exception ex)
        {
            //var code = HttpStatusCode.InternalServerError; // 500 if unexpected
            var code = StatusCodes.Status500InternalServerError;
            string info = "服务器内部错误,无法完成请求";
            if (ex is Exception)
            {
                code = 401;
                info = ex.Message == "" ? "未登录" : ex.Message;

            }
            else if (ex is UnAuthorizeException)
            {
                code = 401;
                info = ex.Message == "" ? "无权访问" : ex.Message;
            }
            else
            {
                switch (context.Response.StatusCode)
                {
                    case 401:
                        info = "没有权限";
                        break;
                    case 404:
                        info = "未找到服务";
                        break;
                    case 403:
                        info = "服务器理解请求客户端的请求,但是拒绝执行此请求";
                        break;
                    case 500:
                        info = "服务器内部错误,无法完成请求";
                        break;
                    case 502:
                        info = "请求错误";
                        break;
                    default:
                        info = ex.Message;
                        break;
                }

            }


            _logger.LogError(info); // todo:可记录日志,如通过注入Nlog等三方日志组件记录

            var result = JsonConvert.SerializeObject(new { Coede= code.ToString(), Message = info });
            context.Response.ContentType = "application/json";
            context.Response.StatusCode = code;
            return context.Response.WriteAsync(result);
        }
    }
}

管道的添加顺序决定了它的执行顺序,所以如果您想扩大异常捕获的范围,可以将该管道放置在 Configure 的第一行。 但是!! 您会发现,这个默认的AspNet Core项目不是已经在第一行弄了一个异常处理么?

if (env.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
}
else
{
    app.UseExceptionHandler("/Error");
}

这行代码大家在初始化新AspNetCore项目时就会看到,也有可能您只有上半段,这和模板有关系。不过这都没有关系,它的作用就是捕获和处理异常而已。关于 UseDeveloperExceptionPage 该扩展咱们就不多说了,它的意思是:对于开发模式,一旦报错就会跳转到错误堆栈页面。 而第二个 UseExceptionHandler 就很有意思了,从它命名就可以看出,它肯定是个错误拦截程序。那么它和咱们自定义的异常处理管道有什么区别呢?

“不指定肯定有个默认吧!” 是的,它就是默认的错误处理。所以,它其实也是一个中间件,它的真身叫做 ExceptionHandlerMiddleware。在使用 UseExceptionHandler 方法时,我们可以选填各种参数。比如上方的代码,填入了 "/Error" 参数,表示当产生异常的时候,将定向到对应路径,此处就定位的是: “http://localhost:5001/Error” 。当然您也可以随意指定页面,比如 漂亮的乔殿下页面。????

创建 HandleException(HttpContext context, Exception e) 处理异常,判断是 Development 环境下,输出详细的错误信息,非 Development 环境仅提示调用者“抱歉,出错了”,同样,在 Startup.cs 中将 ExceptionMiddleware 加入管道中

//ExceptionMiddleware 加入管道
app.UseMiddleware<ExceptionMiddleware>();

 

通过依赖注入和管道中间件两种不同的全局捕获异常处理。实际项目中,也是应当区分不同的业务场景,输出不同的日志信息,不管是从安全或者是用户体验友好性上面来说,都是非常值得推荐的方式,全局异常捕获处理,完全和业务剥离。

 

IExceptionFilter 作为MVC中间件之间的内容,它需要MVC在发现错误之后将错误信息提交给它处理,因此它的错误处理范围仅限于MVC中间件。所以,假如我们需要捕获MVC中间件之前的一些错误,其实是捕获不到的。 而对于ExceptionHandlerMiddleware中间件来说就很简单了,它作为第一个中间件,凡是在它之后的所有错误它都能够捕获得到。

那么这么看来是否IExceptionFilter就毫无用武之地了呢? 非也,假如您想在MVC发生异常时快速捕获和处理,使用过滤器其实是您不错得选择,如果您仅仅关心控制器之间的异常,那么过滤器也是很好的选择。

还记得刚开始我们在过滤器中说过的这一行代码吗:context.ExceptionHandled = true;。如果在IExceptionFilter中将异常标记为已经处理之后,则第一道异常处理中间件就认为没有错误了,不会进入到处理逻辑中。所以,如果咱们不把该属性改为 true,很有可能出现拦截结果被覆盖的情况。

 

相关文章:

  • 2021-09-28
  • 2021-10-06
  • 2021-07-12
  • 2021-05-28
  • 2022-12-23
  • 2023-02-18
  • 2021-07-06
  • 2021-09-13
猜你喜欢
  • 2022-01-02
  • 2019-07-03
  • 2022-12-23
  • 2021-09-27
  • 2021-06-03
  • 2022-12-23
相关资源
相似解决方案