索引网站有哪些,东营垦利,织梦文章采集到wordpress,中信银行门户网站系统文章目录 中间件#xff1a;掌控请求处理过程的关键1. 中间件1.1 中间件工作原理1.2 中间件核心对象 2.异常处理中间件:区分真异常和逻辑异常2.1 处理异常的方式2.1.1 日常错误处理--定义错误页的方法2.1.2 使用代理方法处理异常2.1.3 异常过滤器 IExceptionFilter2.1.4 特性过… 文章目录 中间件掌控请求处理过程的关键1. 中间件1.1 中间件工作原理1.2 中间件核心对象 2.异常处理中间件:区分真异常和逻辑异常2.1 处理异常的方式2.1.1 日常错误处理--定义错误页的方法2.1.2 使用代理方法处理异常2.1.3 异常过滤器 IExceptionFilter2.1.4 特性过滤 ExceptionFilterAttribute2.1.5 异常处理技巧总结 3 静态文件中间件: 前后端分离开发合并部署3.1 静态文件中间件的能力3.2 注册使用非www.root目录 4 文件提供程序:将文件放在任何地方4.1 文件提供程序核心类型4.2 内置文件提供程序 中间件掌控请求处理过程的关键
1. 中间件
1.1 中间件工作原理 1.2 中间件核心对象
IApplicationBuilderRequestDelegate
IApplicationBuilder可以通过委托方式注册中间件委托的入参也是委托这就可以将这些委托注册成一个链如上图所示最终会调用Builder方法返回一个委托这个委托就是把所有的中间件串起来后合并成的一个委托方法Builder的委托入参是HttpContext实际上所有的委托都是对HttpContext进行处理 RequestDelegate是处理整个请求的委托。
中间件的执行顺序和注册顺序是相关的
//注册委托方式,注册自己逻辑// 对所有请求路径app.Use(async (context, next) {await next();await context.Response.WriteAsync(Hello2);});// 对特定路径指定中间件,对/abc路径进行中间件注册处理app.Map(/abc, abcBuilder {// Use表示注册一个完整的中间件,将next也注册进去abcBuilder.Use(async (context, next) {await next();await context.Response.WriteAsync(abcHello);});});// Map复杂判断,判断当前请求是否符合某种条件app.MapWhen(context {return context.Request.Query.Keys.Contains(abc);}, builder {// 使用Run表示这里就是中间件的执行末端,不再执行后续中间件builder.Run(async context {await context.Response.WriteAsync(new abc);});});应用程序一旦开始向Response进行write时,后续的中间件就不能再操作Head,否则会报错 可以通过context.Resopnse.HasStarted方法判断head是否已经被操作
设计自己的中间件 中间件的设计时才有的约定的方式即在方法中包含Invoke或者InvokeAsync如下
public class MyMiddleware{private readonly RequestDelegate next;private readonly ILoggerMyMiddleware logger;public MyMiddleware(RequestDelegate next,ILoggerMyMiddleware logger){this.next next;this.logger logger;}public async Task InvokeAsync(HttpContext context){using (logger.BeginScope(TraceIndentifier:{TraceIdentifier},context.TraceIdentifier)){logger.LogDebug(Start);await next(context);logger.LogDebug(End);}}}public static class MyBuilderExtensions
{public static IApplicationBuilder UseMyMiddleware(this IApplicationBuilder app){return app.UseMiddlewareMyMiddleware();}
}// 中间件使用
app.UseMyMiddleware();
2.异常处理中间件:区分真异常和逻辑异常
2.1 处理异常的方式
异常处理页异常处理匿名委托方法IExceptionFilterExceptionFilterAttribute
// startup中的Configureif (env.IsDevelopment()){app.UseDeveloperExceptionPage();// 开发环境下的异常页面,生产环境下是需要被关闭,页面如下图所示app.UseSwagger();app.UseSwaggerUI(c c.SwaggerEndpoint(/swagger/v1/swagger.json, LoggingSerilog v1));
} 2.1.1 日常错误处理–定义错误页的方法
// startup中的Configure
app.UseExceptionHandler(/error);// 控制器
public class ErrprController : Controller
{[Route(/error)]public IActionResult Index(){// 获取上下文中的异常var exceptionHandlerPathFeature HttpContext.Features.GetIExceptionHandlerPathFeature();var ex exceptionHandlerPathFeature?.Error;var knowException ex as IKnowException;if(knowException null){var logger HttpContext.RequestServices.GetServiceILoggerMyExceptionFilterAttribute();logger.LogError(ex,ex.Message);knowException KnowException.Unknow;}else{knowException KnowException.FromKnowException(knowException);}return View(knowException);}
}// 定义接口
public interface IKnowException
{public string Message {get;}public int ErrorCode {get;}public object[] ErrorData {get;}
}// 定义实现
public class KnowException : IKnowException
{public string Message {get;private set;}public int ErrorCode {get;private set;}public object[] ErrorData {get;private set;}public readonly static IKnowException Uknow new KnowException{Message 未知错误,ErrorCode 9999};public static IKnowException FromKnowException(IKnowException exception){return new KnowException{Message exception.Message,ErrorCode exception.ErrorCode,ErrorData exception.ErrorData};}
}// 需要定义一个错误页面 index.html,输出错误Message和ErrorCode2.1.2 使用代理方法处理异常
// startup中的Configure
app.UseExceptionHandler(errApp
{errApp.Run(async context {var exceptionHandlerPathFeature HttpContext.Features.GetIExceptionHandlerPathFeature();var ex exceptionHandlerPathFeature?.Error;var knowException ex as IKnowException;if(knowException null){var logger HttpContext.RequestServices.GetServiceILoggerMyExceptionFilterAttribute();logger.LogError(exceptionHandlerPathFeature.Error,exceptionHandlerPathFeature.Error.Message);knowException KnowException.Unknow;context.Response.StatusCode StatusCodes.Status500InternalServerError;}else{knowException KnowException.FromKnowException(knowException);context.Response.StatusCode StatusCodes.Status200OK;}var jsonOptions context.RequestServices.GetServiceOptionsJsonOptions();context.Response.ContextType application/json;charsetutf-8;await context.Response.WriteAsync(System.Text.Json.JsonSerializer(knowException,jsonOptions.Value));});
});
未知异常输出Http500响应已知异常输出Http200 因为监控系统会对Http响应码进行识别如果返回的500比率比较高的时候会认为系统的可用性有问题告警系统会发出警告。对已知异常进行200响应能够让告警系统正常运行能够正确识别系统一些未知的错误使告警系统更加灵敏避免了业务逻辑的异常干扰告警系统
2.1.3 异常过滤器 IExceptionFilter
异常过滤器是作用在整个MVC框架体系之下在MVC整个声明周期中发生作用也就是说它只能工作早MVC Web Api的请求周期里面
// 自定义异常过滤器
public class MyException : IExceptionFilter
{public void OnException(ExceptionContext context){IKnowException knowException context.Exception as IKnowException;if(knowException null){var loger context.HttpContext.RequestServices.GetServiceILoggerMyExceptionFilterAttribute();logger.LogError(context.Exception,context.Exception.Message);knowException KnowException.UnKnow;context.HttpContext.Response.StatusCode StatusCodes.Status500InternalServerError;}else{knowException KnowException.FromKnowException(knowException);context.HttpContext.Response.StatusCode StatusCodes.Status200OK;}context.Result new JsonResult(knowException){ContextType application/json:charsetutf-8}}
}// startup注册
public void ConfigureServices(IServiceCollection services)
{services.AddMvc(mvcoption {mvcOptions.Filters.AddMyExceptionFilter();}).AddJsonOptions(jsonOptions {jsonOptions.JsonSerializerOptions.Encoder System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscapt});
}
2.1.4 特性过滤 ExceptionFilterAttribute
public class MyExceptionFilterAttriburte : ExceptionFilterAttribute
{public override void OnException(ExceptionContext context){IKnowException knowException context.Exception as IKnowException;if(knowException null){var logger context.HttpContext.RequestServices.GetServicesILoggerMyExceptionFilterAttribute();logger.LogError(context.Exception,context.Exception.Message);knowException KnowException.UnKnow;context.HttpContext.Response.StatusCode StatusCodes.Status500InternalServerError;}else{knowException KnowException.FromKnowException(knowException);context.HttpContext.Response.StatusCode StatusCodes.Status200OK;}context.Result new JsonResult(knowException){ContextType application/json:charsetutf-8}}
}// 使用方式
在Controller控制器上方标注[MyExceptionFilter]
或者在 startup中ConfigureServices注册
services.AddMvc(mvcoption {mvcOptions.Filters.AddMyExceptionFilterAttribute();});2.1.5 异常处理技巧总结
用特定的异常类或接口表示业务逻辑异常为业务逻辑异常定义全局错误码为未知异常定义定义特定的输出信息和错误码对于已知业务逻辑异常响应HTTP 200(监控系统友好)对于未预见的异常响应HTTP 500为所有的异常记录详细的日志
3 静态文件中间件: 前后端分离开发合并部署
3.1 静态文件中间件的能力
支持指定相对路径支持目录浏览支持设置默认文档支持多目录映射
// startup的Configure方法中
app.UseDefaultFiles();// 设置默认访问根目录文件index.html
app.UseStaticFiles();// 将www.root目录映射出去
如果需要浏览文件目录,需要如下配置
// startup中的ConfigureServices中配置
services.AddDirectoryBrowser();// startup的Configure方法中
app.UseDirectoryBrowser();
app.UseStaticFiles();
3.2 注册使用非www.root目录
// startup的Configure方法中
app.UseStaticFiles();app.UseStaticFiles(new StaticFileOptions
{// 将程序中名为file文件目录注入RequestPath /files,// 设置文件指定访问路径,将文件目录映射为指定的Url地址FileProvider new PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory(),file))
});
实际生产中会遇到将非api请求重定向到指定目录,采用如下配置
// startup的Configure方法中
app.MapWhen(context
{return !context.Request.Path.Value.StartWith(/api);
},appBuilder
{var option new RewriteOptions();option.AddRewrite(.*,/index.html,true);appBuilder.UseRewriter(option);appBuilder.UseStaticFiles();
});4 文件提供程序:将文件放在任何地方
4.1 文件提供程序核心类型
IFileProviderIFileInfoIDirectoryContexts
4.2 内置文件提供程序
PhysicalFileProvider⇒ 物理文件提供程序EmbeddedFileProvider ⇒ 嵌入式文件提供程序CompositeFileProvoder ⇒ 组合文件提供程序,将各种文件程序组合成一个目录
// 映射指定目录文件- 物理文件
IFileProvider provider1 new PhysicalFileProvider(AppDomain.CurrentDomain.BaseDirectory);
// 获取文件目录下内容
var contents provider1.GetDirectoryContents(/);
// 输出文件信息
foreach (var item in contents)
{var stream item.CreateReadStream();// 获取文件流Console.WriteLine(item.Name);
}// 嵌入式文件
IFileProvider fileProvider2 new EmbeddedFileProvider(typeof(Program).Assembly);
var html fileProvider2.GetFileInfo(file.html);// file.html文件属性设置为嵌入的资源// 组合文件提供程序
IFileProvider fileProvider3 new CompositeFileProvider(provider1,fileProvider2);
var contexts3 fileProvider3.GetDirectoryContents(/);