简介
Abp 框架本身针对内部抛出异常进行了统一拦截,并且针对不同的异常也会采取不同的处理策略。在 Abp 当中主要提供了以下几种异常类型:
异常类型 | 描述 |
AbpException |
Abp 框架定义的基本异常类型,Abp 所有内部定义的异常类型都继承自本类 |
AbpInitializationException |
Abp 框架初始化时出现错误所抛出的异常 |
AbpDbConcurrencyException |
当 EF Core 执行数据库操作时产生了 DbUpdateConcurrencyException 异常 的时候 Abp 会封装为本异常并且抛出 |
AbpValidationException |
用户调用接口时,输入的DTO 参数有误会抛出本异常 |
BackgroundJobException |
后台作业执行过程中产生的异常 |
EntityNotFoundException |
当仓储执行 Get 操作时,实体未找到引发本异常 |
UserFriendlyException |
如果用户需要将异常信息发送给前端,请抛出本异常 |
AbpRemoteCallException |
远程调用一场,当使用 Abp 提供的 AbpWebApiClient 产生问题的时候 会抛出此异常 |
一 启动流程
Abp 框架针对异常拦截的处理主要使用了 ASP .NET CORE MVC 过滤器机制,当外部请求接口的时候,所有异常都会被 Abp 框架捕获。Abp 异常过滤器的实现名称叫做 AbpExceptionFilter,它在注入 Abp 框架的时候就已经被注册到了 ASP .NET Core 的 MVC Filters 当中了。具体流程图如下:
2 代码分析
2.1异常返回
abp 本身针对异常信息的核心处理就在于它的 AbpExceptionFilter 过滤器,过滤器实现很简单。它首先继承了 IExceptionFilter 接口,实现了其 OnException() 方法,只要用户请求接口的时候出现了任何异常都会调用 OnException() 方法。而在 OnException() 方法内部,Abp 根据不同的异常类型进行了不同的异常处理。
返回值格式:
此处就是返回的错误码部分,HttpStatusCode默认指定成了500,对前端判断来说有歧义。对于一些默认封装好的处理Http请求的组件,有一部分是不支持开发者去处理这个500以上的错误信息的,或者这个错误码对于一些前端开发来说很困惑。 因为一般500的错误都是服务器发生了异常,被动的抛出的一个错误,在很多客户端是不给用户展示的,所以一些HttpClient对500以上的错误就默认处理,提示发生服务器内部错误,在自己内部消化了这个错误导致开发人员不能自由的处理Http请求。
3 自定义异常处理
3.1 添加一个CustomeException.cs,继承UserFriendlyException,添加一个属性HttpCode
/// <summary>
/// 自定义错误状态吗
/// </summary>
public class CustomeException : UserFriendlyException
{
public CustomeException(int code, string message, string details)
: this((int)HttpStatusCode.BadRequest, code, message, details)
{
}
public CustomeException(HttpStatusCode httpCode, int code, string message, string details)
: this((int)httpCode, code, message, details)
{
}
public CustomeException(int httpCode, int code, string message, string details)
: base(code, message, details)
{
HttpCode = httpCode;
}
/// <summary>
/// http 状态码
/// </summary>
public int HttpCode { get; set; }
}
3.2 添加CustomeApiExceptionFilterAttribute,继承AbpApiExceptionFilterAttribute,然后重写GetStatusCode方法
public class CustomeApiExceptionFilterAttribute : AbpApiExceptionFilterAttribute, ITransientDependency
{
public CustomeApiExceptionFilterAttribute(IAbpWebApiConfiguration configuration) : base(configuration)
{
}
protected override HttpStatusCode GetStatusCode(HttpActionExecutedContext context)
{
var customException = (context.Exception as CustomeException);
if (customException != null)
{
return
(HttpStatusCode)customException.HttpCode;
}
else
{
return base.GetStatusCode(context);
}
}
public void UseThis()
{
var filters = Configuration.HttpConfiguration.Filters;
var filterInfo = filters.FirstOrDefault(h => h.Instance is AbpApiExceptionFilterAttribute);
if (filterInfo != null) {
filters.Remove(filterInfo.Instance);
}
filters.Add(this);
}
}
3.3 在statup文件中注册重写的过滤器
注意代码中的的数字,测试发现如果不加入手动排序,ioc容器会把重写的过滤器置于次要地位,过滤器会不起作用
services.AddMvc(
options => {
options.Filters.AddService(typeof(CustomeApiExceptionFilter), order: 0);
options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());
}
).AddJsonOptions(options => options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss")
.AddWebApiConventions();
以上三个步骤之后,在代码中抛出CustomeException就可以自定义httpStatusCode了。