需求:
1、对异常进行捕获记录日志 并且修改返回值给前端
解释:
ILogger4是自定义的一个日志,更改它就好
解决方案1:
使用中间件进行异常捕获并且修改其返回值
public class ErrorMiddleware { private readonly RequestDelegate _next; ILogger4<ErrorMiddleware> logger4; public ErrorMiddleware(RequestDelegate next,ILogger4<ErrorMiddleware> logger4) { _next = next; this.logger4 = logger4; } public async Task Invoke(HttpContext httpContext) { try { await _next(httpContext); } catch (Exception e) { logger4.LogError(e,e.Message+" "+e.StackTrace); throw e; } } }
这一步简单,从源码里 ExceptionHandlerMiddleware.cs类里 Copy的代码
使用中间件进行修改返回值
public class ResultMiddleware { private readonly RequestDelegate _next; public ResultMiddleware(RequestDelegate next) { _next = next; } public async Task Invoke(HttpContext httpContext) { await _next(httpContext);
string bodyString = "<p>不好意思 系统正在升级维护 请稍后再试</p>";
var by = Encoding.UTF8.GetBytes(bodyString);
var heard =(Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpResponseHeaders)httpContext.Response.Headers;
heard.HeaderContentLength = by.Length.ToString();
//必须要手动设置请求头的ContentLength大小 才能修改返回值的数据
await httpContext.Response.Body.WriteAsync(by);
}
}
这是从网上copy 修改的代码,不推荐使用 开销太大 转为过滤器
解决方案2:
使用中间件进行异常捕获并且修改其返回值
异常过滤器
/// <summary> /// 异常过滤器 /// </summary> public class ErrorFilter :Attribute,IExceptionFilter { ILogger4<ErrorFilter> logger4; /// <summary> /// 标签 /// </summary> public ErrorFilter() { } /// <summary> /// 全局配置 /// </summary> /// <param name="logger4"></param> public ErrorFilter(ILogger4<ErrorFilter> logger4) { this.logger4 = logger4; } public void OnException(ExceptionContext context) { var e = context.Exception; logger4.LogError(e, e.Message + " " + e.StackTrace); context.Result = new JsonResult(new BaseResult(e.Message)); } }
方法过滤器
/// <summary> /// 对打上该标记的 返回结果为JsonResult的请求进行Result包装 /// </summary> public class ApiResultFilter : Attribute, IActionFilter { /// <summary> /// 执行方法体之后 /// </summary> /// <param name="context"></param> public void OnActionExecuted(ActionExecutedContext context) { var result = context.Result; if (result!=null &&result is JsonResult resulta) { context.Result = new JsonResult(new BaseResult(resulta.Value)); } } /// <summary> /// 执行方法体之前 /// </summary> /// <param name="context"></param> public void OnActionExecuting(ActionExecutingContext context) { //不做修改 } }
可以使用标签的方法
/// <summary> /// 测试 返回过滤器 /// </summary> /// <returns></returns> [ErrorFilter] [ApiResultFilter] [HttpGet] public IActionResult TestReuslt() { throw new Exception("AA"); var obj = new { A = "321" }; return Json(obj); }
也可以使用全局配置的方法
//注册过滤器 services.AddSingleton<ApiResultFilter>(); services.AddSingleton<ErrorFilter>(); services.AddMvc( config => { config.Filters.AddService(typeof(ApiResultFilter)); config.Filters.AddService(typeof(ErrorFilter)); }) .SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
注意:
打上的标签无法获取IOC容器
不要使用全局配置与标签一起使用 会造成多次调用
在这里推荐使用过滤器而不是中间件,
贴上一张大佬的过滤器调用图
结果: