Abp Vnext 中如何统一接口返回值

ABP Vnext Vue 的实现

{
    // 返回格式类似这种
    "success": false,
    "message": "请求失败",
    "data": null,
    "code": 500
}
  • 定义返回类型
public class WrapResult<T>
{
    private bool Success { get; set; }
    private string Message { get; set; }
    private T Data { get; set; }
    private int Code { get; set; }
    public WrapResult()
    {
        Success = true;
        Message = "Success";
        Data = default;
        Code = 200;
    }
    public void SetSuccess(T data, string message = "Success", int code = 200)
    {
        Success = true;
        Data = data;
        Code = code;
    }
    public void SetFail(string message = "Fail", int code = 500)
    {
        Success = false;
        Message = message;
        Code = code;
    }
}

实现思路

  • 定义 WrapResultAttribute
public class WrapResultAttribute : Attribute
{
}
  • 实现 IAsyncExceptionFilter(拦截异常,抛异常时指定返回格式)
public class ResultExceptionFilter : IFilterMetadata, IAsyncExceptionFilter, ITransientDependency
{
    private ILogger<ResultExceptionFilter> Logger { get; set; }
    private readonly IExceptionToErrorInfoConverter _errorInfoConverter;
    private readonly IHttpExceptionStatusCodeFinder _statusCodeFinder;
    private readonly IJsonSerializer _jsonSerializer;
    private readonly AbpExceptionHandlingOptions _exceptionHandlingOptions;
    public ResultExceptionFilter(
        IExceptionToErrorInfoConverter errorInfoConverter,
        IHttpExceptionStatusCodeFinder statusCodeFinder,
        IJsonSerializer jsonSerializer,
        IOptions<AbpExceptionHandlingOptions> exceptionHandlingOptions)
    {
        _errorInfoConverter = errorInfoConverter;
        _statusCodeFinder = statusCodeFinder;
        _jsonSerializer = jsonSerializer;
        _exceptionHandlingOptions = exceptionHandlingOptions.Value;
        Logger = NullLogger<ResultExceptionFilter>.Instance;
    }
    public async Task OnExceptionAsync(ExceptionContext context)
    {
        if (!ShouldHandleException(context))
        {
            return;
        }
        await HandleAndWrapException(context);
    }
    protected virtual bool ShouldHandleException(ExceptionContext context)
    {
        if (context.ActionDescriptor.AsControllerActionDescriptor().ControllerTypeInfo.GetCustomAttributes(typeof(WrapResultAttribute), true).Any())
        {
            return true;
        }
        if (context.ActionDescriptor.GetMethodInfo().GetCustomAttributes(typeof(WrapResultAttribute), true).Any())
        {
            return true;
        }

        return false;
    }
    protected virtual async Task HandleAndWrapException(ExceptionContext context)
    {
        // 处理异常信息
        context.HttpContext.Response.Headers.Add(AbpHttpConsts.AbpErrorFormat, "true");
        var statusCode = (int)_statusCodeFinder.GetStatusCode(context.HttpContext, context.Exception);
        context.HttpContext.Response.StatusCode = 200;
        var remoteServiceErrorInfo = _errorInfoConverter.Convert(context.Exception, _exceptionHandlingOptions.SendExceptionsDetailsToClients);
        remoteServiceErrorInfo.Code = context.HttpContext.TraceIdentifier;
        remoteServiceErrorInfo.Message = SimplifyMessage(context.Exception);
        // 返回格式统一
        var result = new WrapResult<object>();
        result.SetFail(remoteServiceErrorInfo.Message);
        // HttpResponse
        context.Result = new ObjectResult(result);
        // 写日志
        var logLevel = context.Exception.GetLogLevel();
        var remoteServiceErrorInfoBuilder = new StringBuilder();
        remoteServiceErrorInfoBuilder.AppendLine($"---------- {nameof(RemoteServiceErrorInfo)} ----------");
        remoteServiceErrorInfoBuilder.AppendLine(_jsonSerializer.Serialize(remoteServiceErrorInfo, indented: true));
        Logger.LogWithLevel(logLevel, remoteServiceErrorInfoBuilder.ToString());
        Logger.LogException(context.Exception, logLevel);
        await context.HttpContext
            .RequestServices
            .GetRequiredService<IExceptionNotifier>()
            .NotifyAsync(
                new ExceptionNotificationContext(context.Exception)
            );
        context.Exception = null; //Handled!
    }
    private string SimplifyMessage(Exception error)
    {
        string message = string.Empty;
        switch (error)
        {
            case AbpAuthorizationException e:
                return message = "Authenticate failure!";
            case AbpValidationException e:
                return message = "Request param validate failure!";
            case EntityNotFoundException e:
                return message = "not found the entity!";
            case BusinessException e:
                return message = $"{e.Message}";
            case NotImplementedException e:
                return message = "not implement!";
            default:
                return message = "server internal error!";
        }
    }
}

注册 Filter

 public override void ConfigureServices(ServiceConfigurationContext context)
 {
    context.Services.AddMvc(options =>
        {
            options.Filters.Add(typeof(ResultExceptionFilter));
        });
 }

使用

  • 在 Controller 上或者 Action 上打上 WrapResultAttribute 特性
  • 例如
    [Route("Permissions")]
    [WrapResult]
    public class PermissionController : AbpProController,IRolePermissionAppService
    {
        private readonly IRolePermissionAppService _rolePermissionAppService;

        public PermissionController(IRolePermissionAppService rolePermissionAppService)
        {
            _rolePermissionAppService = rolePermissionAppService;
        }

        [HttpPost("tree")]
        [SwaggerOperation(summary: "获取角色权限", Tags = new[] { "Permissions" })]
        [WrapResult] //控制器上打了 action上就不需要
        public Task<PermissionOutput> GetPermissionAsync(GetPermissionInput input)
        {
            return _rolePermissionAppService.GetPermissionAsync(input);
        }

    }
上一篇:异常Exception(未完)


下一篇:python的异常处理