文章摘要:本文介绍了两种统一API接口返回值的实现方式。传统方式通过定义ResponseModel和ResponseModel<T>基类,包含状态码、消息和数据字段,并提供了扩展方法SetSuccess和SetFail来设置响应结果。ABP框架方式则更全面,通过WrapResult<T>类、WrapResultAttribute特性及ResultExceptionFilter过滤器实现,能自动处理异常并统一返回格式。后者还包含日志记录、状态码转换等功能,通过在控制器或Action上添加WrapResult特性即可启用统一响应格式。两种方式都实现了成功/失败状态的标准化返回,提高了API接口的一致性。
传统常规方式统一接口返回值
Domain.Shared
// <summary>
/// 响应结果
/// </summary>
public class ResponseModel
{
//响应状态码
public ResponseCode code { get; set; }
/// <summary>
/// 响应消息
/// </summary>
public string message { get; set; }
}
/// <summary>
/// 有对象的响应结果
/// </summary>
/// <typeparam name="T"></typeparam>
public class ResponseModel<T> : ResponseModel
{
public T data { get; set; }
}
public enum ResponseCode
{
Success = 0,
Fail = 1
}
public static class ResponseExtend
{
public static ResponseModel SetSuccess(this ResponseModel response, string message = "")
{
ResponseModel result = new ResponseModel();
result.code = ResponseCode.Success;
result.message = message == string.Empty ? "操作成功" : message;
return result;
}
public static ResponseModel<T> SetSuccess<T>(this ResponseModel<T> response, T data = default, string message = "")
{
response.code = ResponseCode.Success;
response.message = message == string.Empty ? "操作成功" : message;
response.data = data;
return response;
}
public static ResponseModel SetFail(this ResponseModel response, string message = "")
{
response.code = ResponseCode.Fail;
response.message = message == string.Empty ? "操作失败" : message;
return response;
}
public static ResponseModel<T> SetFail<T>(this ResponseModel<T> response, string message = "", T data = default)
{
response.code = ResponseCode.Fail;
response.message = message == string.Empty ? "操作成功" : message;
response.data = data;
return response;
}
Application
public async Task<ResponseModel<PagedResultDto<PageSPWxTagOutput>>> SPPageAsync(PageSPWxTagInput input)
{
ResponseModel<PagedResultDto<PageSPWxTagOutput>> response = System.Text.Json.JsonSerializer.Deserialize<ResponseModel<PagedResultDto<PageSPWxTagOutput>>>(
System.Text.Json.JsonSerializer.Serialize(new { code = 0, msg = "更新成功",date=new PagedResultDto<PageSPWxTagOutput>() }));
try
{
}
catch (Exception ex)
{
response.SetFail("获取SDK数据失败:" + ex.Message);
return response;
}
}
/// <summary>
/// 创建盛派微信标签
/// </summary>
public async Task<ResponseModel> CreateAsync(CreateSPWxTagInput input)
{
ResponseModel response = System.Text.Json.JsonSerializer.Deserialize<ResponseModel>(
System.Text.Json.JsonSerializer.Serialize(new { code = 0, msg = "创建成功" }));
//todo 选中的公众号
if (Guid.TryParse(input.idaccessToken, out Guid guid))
{
}
else
{
response.SetFail("转换失败:字符串不是有效的 GUID 格式");
return response;
}
var aAuthorizer_Access_Token = await _SpCommonAppService.getAuthorizer_Access_Token(guid);
if (string.IsNullOrWhiteSpace(aAuthorizer_Access_Token))
{
response.SetFail("获取aAuthorizer_Access_Token失败");
return response;
}
try {
}
catch (Exception ex)
{
response.SetFail("获取SDK数据失败:" + ex.Message);
return response;
}
/
return response;
}
httpAPI
[HttpPost("Create")]
[SwaggerOperation(summary: "创建盛派微信标签", Tags = new[] { "SPWxTags" })]
public async Task<ResponseModel> CreateAsync(CreateSPWxTagInput input)
{
return await _sPWxTagAppService.CreateAsync(input);
}
[HttpPost("SPPage")]
[SwaggerOperation(summary: "SP分页查询盛派微信标签", Tags = new[] { "SPWxTags" })]
public async Task<ResponseModel<PagedResultDto<PageSPWxTagOutput>>> SPPageAsync(PageSPWxTagInput input)
{
return await _sPWxTagAppService.SPPageAsync(input);
}
---
ABP Vnext Vue 的实现
-
在使用 abp 的过程中,如果提供给第三方接口要实现返回值统一需要怎么做?
{
// 返回格式类似这种
"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);
}
}
ABP.Next系列01-有啥?像啥?infrastructure -Fstyle-优快云博客
ABP.Next系列02 搭个API框架要多久 项目下载 运行 -Fstyle_【abp vnext】下载并运行web api项目详细教程文档-优快云博客