WebAPI
本页是 AgileLabs Framework WebAPI 的主题页,聚合返回封包、异常处理、认证授权和 Swagger 对齐约定。正式规则请优先阅读 框架规范 / WebAPI 规范。
适用场景
ApiController控制器。- 使用
EnvelopMessage、异常过滤器和 API 异常处理器的项目。 - 需要接入 ASP.NET Core 认证授权的服务。
必须遵守
- 标准 API 响应必须保持统一封包;对前端暴露的默认协议固定为
{ data, code, msg, errMsg, tid }。 - API 过滤器同时配置
ExceptionHandlerFilter与EnvelopFilterAttribute,除非接口显式跳过封包。 - 模型验证与业务异常统一走异常处理链,不在每个 Action 手写重复
ModelState分支和catch(Exception)JSON 拼装。 - 认证授权接入必须统一,要么框架集成,要么宿主显式接入,不做半自动半手工混用。
/fwdev、/req_stat、/jobs等敏感入口必须受保护。- 业务可预期错误统一映射到规范化返回,不把数据库异常或系统异常堆栈直接返回给前端。
推荐做法
- 用
EnvelopFilterAttribute或项目级统一封包层承接成功返回包装。 - 用
IApiExceptionProcessor承接项目级异常映射。 - 认证规则统一使用 ASP.NET Core 标准授权机制。
- Swagger 文档对齐真实响应封包,避免文档和实际返回不一致。
- 开放接口、回调接口和健康检查接口单独标明匿名访问策略。
源码入口
AgileLabs.WebApp/AspNet/WebApis/Filters/EnvelopFilterAttribute.cs:成功响应统一封包。AgileLabs.WebApp/AspNet/WebApis/Filters/ExceptionHandlerFilter.cs:模型校验和异常总入口。AgileLabs.WebApp/AspNet/WebApis/Filters/DefaultApiExceptionProcessor.cs:把异常映射成EnvelopMessage。AgileLabs.WebApp/AspNet/WebApis/Exceptions/ApiException.cs:业务错误基类。AgileLabs.WebApp/AspNet/WebApis/Exceptions/ModelValidateException.cs:模型验证错误。
成功返回链路
典型的 API 成功响应不是由 Controller 自己手工包装,而是由过滤器在 Action 完成后统一封包。这样做的意义是:业务层只表达真实业务对象,前端永远拿到稳定协议。
sequenceDiagram
participant Client as Client
participant Controller as ApiController
participant Action as Action
participant Envelop as EnvelopFilterAttribute
Client->>Controller: HTTP Request
Controller->>Action: 执行业务逻辑
Action-->>Controller: 返回 ObjectResult / JsonResult / EmptyResult
Controller->>Envelop: OnActionExecuted()
Envelop->>Envelop: 检查 IgnoreEnvelopAttribute
Envelop->>Envelop: 检查是否为 ApiController
Envelop-->>Client: OkObjectResult(EnvelopMessage)
最小闭环示例:
[ApiController]
[Route("api/orders")]
public class OrdersController : ControllerBase
{
[HttpGet("{id}")]
public async Task<OrderDto> GetAsync(Guid id)
{
return await _service.GetAsync(id);
}
}
只要宿主已经挂上 EnvelopFilterAttribute,上面的 OrderDto 就会被统一转换成类似结果:
{
"data": {
"id": "f1f7c56b-49b8-4cc7-bc22-2ab1cf74b7ae",
"orderNo": "SO-20260412-001"
},
"code": 200,
"msg": null,
"errMsg": null,
"tid": "trace-id"
}
异常处理链路
ExceptionHandlerFilter 同时承担两件事:Action 执行前先把 ModelState 失败转换成 ModelValidateException;执行中如果出现异常,再交给 IApiExceptionProcessor 做统一映射。
sequenceDiagram
participant Client as Client
participant Filter as ExceptionHandlerFilter
participant Action as Action
participant Processor as IApiExceptionProcessor
participant Result as JsonResult
Client->>Filter: 请求进入 Action Filter
Filter->>Filter: 检查 ModelState
alt 模型校验失败
Filter->>Processor: Process(ModelValidateException)
Processor-->>Result: EnvelopMessage(code/msg/errMsg)
Result-->>Client: 200 + 规范错误封包
else Action 抛出业务/系统异常
Filter->>Action: 执行 Action
Action-->>Filter: 抛出 ApiException / DbException / Exception
Filter->>Processor: Process(exception)
Processor-->>Result: JsonResult(EnvelopMessage)
Result-->>Client: 200 + 规范错误封包
end
默认处理器的行为可以概括成这张表:
| 异常类型 | 处理器行为 | 对前端的结果 |
|---|---|---|
ModelValidateException |
不输出错误日志,提取字段错误 | 返回参数错误封包 |
ApiException |
不输出错误日志,保留业务码 | 返回业务错误封包 |
DbException |
映射为数据库错误 | 返回统一数据库错误码 |
其他 Exception |
兜底处理 | 返回统一 500 封包 |
自定义项目级处理器的最小写法:
public class ProjectApiExceptionProcessor : DefaultApiExceptionProcessor
{
protected override EnvelopMessage ProcessException(ApiException exception, ExceptionProcessContext processContext)
{
return new EnvelopMessage((int)exception.Code, exception.HintMessage, exception.Message);
}
}
认证授权接入位置
- 请求管道阶段里,框架会在
UseRouting()之后、UseEndpoints()之前插入认证授权。 - 如果
buildContext.FeatureSwitch.IsIntegrateAspNetAuthentication为真,框架会自动执行UseAuthentication()和UseAuthorization()。 - 如果项目不走框架集成,就必须在宿主自己的管道注册里完整接入,不要出现“控制器上写了
[Authorize],但管道里没跑授权中间件”的半接入状态。
Swagger 与封包对齐点
- Swagger 不是描述 Controller 里返回了什么对象,而是描述最终对前端暴露的协议。
- 如果宿主已启用统一封包,Swagger 文档也必须体现封包后的结构。
- 如果某些 Action 使用
IgnoreEnvelopAttribute,就应把它们标记成特例接口,而不是默认接口。
建议在项目文档或过滤器注册处明确这两类规则:
services.AddControllers(options =>
{
options.Filters.Add<ExceptionHandlerFilter>();
options.Filters.Add<EnvelopFilterAttribute>();
});
常见误接法对照
| 误接法 | 风险 | 正确做法 |
|---|---|---|
Controller 手工 return new JsonResult(...) 拼封包 |
不同接口字段漂移 | 由统一过滤器封包 |
Action 里 catch (Exception) 后直接返回 JSON |
绕开统一异常链 | 抛给 ExceptionHandlerFilter |
只注册 UseAuthentication() |
授权不生效 | 认证和授权一起挂 |
| Swagger 仍描述裸对象 | 前后端理解不一致 | 文档对齐真实封包 |
常见坑
- 有的接口返回裸对象,有的接口返回封包对象。
- 对前端有的接口返回
camelCase,有的接口返回PascalCase。 - 只注册
UseAuthentication()不注册UseAuthorization()。 - 把系统异常堆栈直接返回给前端。
- 在控制器里
catch (Exception)后手动拼 JSON,绕开统一异常处理链。
真实用例
- niusys-webapi:
EnvelopMessage、Swagger 封包适配、JWT + ApiKey。 - gmandarin-backend:宿主层启用
IsIntegrateAspNetAuthentication = true。 - woscm:项目级异常处理器、业务错误码、TraceId 回写。