在C#开发Web API的过程中,不同开发者编写接口时返回的格式往往存在差异,有的直接返回业务实体,有的返回自定义的错误对象,这种不统一的返回格式会大幅增加前端对接的工作量,也容易引发数据处理异常。通过封装统一的API响应格式,可以让所有接口的返回结构保持一致,包含明确的业务状态、提示信息和返回数据,提升接口的规范性和易用性。

设计统一响应基类
首先需要定义一个通用的响应模型,包含所有接口都需要返回的字段,比如状态码、提示信息、返回数据等。状态码可以区分请求成功、参数错误、业务异常等不同场景,提示信息用于向前端说明请求结果,返回数据则承载具体的业务内容。
/// <summary>
/// 通用API响应模型
/// </summary>
/// <typeparam name="T">返回数据的类型</typeparam>
public class ApiResponse<T>
{
/// <summary>
/// 业务状态码
/// </summary>
public int Code { get; set; }
/// <summary>
/// 提示信息
/// </summary>
public string Message { get; set; }
/// <summary>
/// 返回的具体数据
/// </summary>
public T Data { get; set; }
/// <summary>
/// 请求成功时的响应构造
/// </summary>
public static ApiResponse<T> Success(T data, string message = "请求成功")
{
return new ApiResponse<T>
{
Code = 200,
Message = message,
Data = data
};
}
/// <summary>
/// 请求失败时的响应构造
/// </summary>
public static ApiResponse<T> Fail(int code, string message)
{
return new ApiResponse<T>
{
Code = code,
Message = message,
Data = default
};
}
}
封装返回结果帮助方法
为了避免在每个接口中重复编写构造响应对象的代码,可以封装静态帮助类,提供常用的成功、失败返回方法,简化接口编写逻辑。
/// <summary>
/// API响应帮助类
/// </summary>
public static class ApiResponseHelper
{
/// <summary>
/// 返回成功响应
/// </summary>
public static ApiResponse<T> Ok<T>(T data, string message = "请求成功")
{
return ApiResponse<T>.Success(data, message);
}
/// <summary>
/// 返回参数错误响应
/// </summary>
public static ApiResponse<T> BadRequest<T>(string message = "参数错误")
{
return ApiResponse<T>.Fail(400, message);
}
/// <summary>
/// 返回业务异常响应
/// </summary>
public static ApiResponse<T> BusinessError<T>(string message = "业务处理异常")
{
return ApiResponse<T>.Fail(500, message);
}
}
在控制器接口中使用统一返回格式
编写业务接口时,直接调用帮助类的方法返回统一格式的响应即可,不需要再手动构造响应对象,减少重复代码。
[ApiController]
[Route("api/[controller]")]
public class UserController : ControllerBase
{
/// <summary>
/// 获取用户信息
/// </summary>
[HttpGet("{id}")]
public ApiResponse<User> GetUser(int id)
{
if (id <= 0)
{
return ApiResponseHelper.BadRequest<User>("用户ID必须大于0");
}
// 模拟查询用户数据
User user = new User
{
Id = id,
Name = "测试用户",
Age = 25
};
return ApiResponseHelper.Ok(user);
}
/// <summary>
/// 新增用户
/// </summary>
[HttpPost]
public ApiResponse<bool> AddUser(UserInput input)
{
if (string.IsNullOrEmpty(input.Name))
{
return ApiResponseHelper.BadRequest<bool>("用户名称不能为空");
}
// 模拟新增用户逻辑
bool result = true;
return ApiResponseHelper.Ok(result, "用户新增成功");
}
}
/// <summary>
/// 用户实体
/// </summary>
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
/// <summary>
/// 用户新增输入模型
/// </summary>
public class UserInput
{
public string Name { get; set; }
public int Age { get; set; }
}
通过过滤器实现全局响应包装
如果希望所有接口自动被包装成统一格式,不需要在每个接口中手动调用返回方法,可以使用ASP.NET Core的过滤器实现全局拦截处理。当接口返回原始数据时,过滤器会自动将其包装成统一的响应格式。
/// <summary>
/// 全局响应包装过滤器
/// </summary>
public class ApiResponseWrapFilter : IAsyncActionFilter
{
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
var executedContext = await next();
if (executedContext.Result is ObjectResult objectResult)
{
// 如果返回结果已经是ApiResponse类型,不需要再次包装
if (objectResult.Value is ApiResponse<object>)
{
return;
}
// 包装原始返回数据为统一格式
var wrappedResponse = ApiResponse<object>.Success(objectResult.Value, "请求成功");
executedContext.Result = new ObjectResult(wrappedResponse)
{
StatusCode = objectResult.StatusCode
};
}
}
}
然后在Program.cs中注册这个过滤器,就可以让所有接口自动应用统一返回格式:
var builder = WebApplication.CreateBuilder(args);
// 添加控制器并注册全局响应包装过滤器
builder.Services.AddControllers(options =>
{
options.Filters.Add<ApiResponseWrapFilter>();
});
var app = builder.Build();
app.MapControllers();
app.Run();
常用状态码定义建议
为了让响应状态码的含义更清晰,可以定义一个状态码枚举,避免硬编码数字,提升代码可读性:
/// <summary>
/// API响应状态码枚举
/// </summary>
public enum ApiStatusCode
{
/// <summary>
/// 请求成功
/// </summary>
Success = 200,
/// <summary>
/// 参数错误
/// </summary>
BadRequest = 400,
/// <summary>
/// 未授权
/// </summary>
Unauthorized = 401,
/// <summary>
/// 无权限
/// </summary>
Forbidden = 403,
/// <summary>
/// 资源不存在
/// </summary>
NotFound = 404,
/// <summary>
/// 业务异常
/// </summary>
BusinessError = 500
}
修改之前的响应类,使用枚举来设置状态码,代码会更易维护:
public class ApiResponse<T>
{
public int Code { get; set; }
public string Message { get; set; }
public T Data { get; set; }
public static ApiResponse<T> Success(T data, string message = "请求成功")
{
return new ApiResponse<T>
{
Code = (int)ApiStatusCode.Success,
Message = message,
Data = data
};
}
public static ApiResponse<T> Fail(ApiStatusCode code, string message)
{
return new ApiResponse<T>
{
Code = (int)code,
Message = message,
Data = default
};
}
}