ApiCallActivity
分类: 通用步骤
命名空间: CMS.Plugin.FlowManagement.Domain.FlowBusiness.Activitys
基类: ActionActivity
模块: FlowManagement.Domain
概述
ApiCallActivity(调用API)是用于在流程中调用外部 API 接口的节点。它继承自 ActionActivity,支持调用系统互联中配置的 API 接口,并将 API 的响应结果写入流程上下文。该节点支持同步和异步调用模式,可以灵活地从 API 响应中提取所需的数据字段。
ApiCallActivity 是流程与外部系统集成的重要桥梁,通过它可以实现与 ERP、MES、WMS 等系统的数据交互,获取外部数据或触发外部操作。
业务场景
适用场景
- 数据查询: 从外部系统查询产品信息、工单信息、库存信息等
- 数据同步: 将流程数据同步到外部系统
- 业务触发: 触发外部系统的业务操作(如创建订单、发送通知)
- 系统集成: 与第三方系统进行数据交互
- 服务调用: 调用微服务接口获取业务数据
在系统中的作用
ApiCallActivity 在 LMES 流程系统中扮演着系统集成器的角色:
- 调用系统互联中配置的 API 接口
- 处理 API 请求和响应
- 解析 JSON 响应数据
- 将响应数据写入流程上下文
- 处理 API 调用异常
与其他节点的协作
- BusinessActivity: 在 API 调用前准备请求参数,在 API 调用后处理响应数据
- ActionActivity: 作为动作节点,可以配置执行时机
- 其他 API 节点: 可以串联多个 API 调用,实现复杂的集成场景
配置说明
基本配置
| 属性名 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
| ApiId | string | 是 | - | API 编号,调用互联中的 API 接口 |
| Wait | bool | 否 | true | 是否等待执行结束 |
| Authorization | string | 否 | - | 授权信息(请求 Token) |
| Response | HttpParameterModels | 否 | 空集合 | 返回响应参数配置 |
| Action | ActionType | 否 | Execute | 执行时机(继承自 ActionActivity) |
| IsSynchronous | bool | 否 | true | 是否同步执行(继承自 ActionActivity) |
配置项详解
ApiId
说明: API 编号,指定要调用的 API 接口。该 API 必须在系统互联模块中预先配置。
取值范围: 字符串,对应系统互联中配置的 API 编号
注意事项:
- 必须确保指定的 API 在系统中存在
- API 必须已启用且配置正确
- 可以通过流程上下文动态指定 API 编号
Wait
说明: 是否等待 API 执行完成。当设置为 true 时,流程会等待 API 调用完成并获取响应;设置为 false 时,流程会立即继续执行,不等待 API 响应。
取值范围: true 或 false
注意事项:
- Wait=true(默认): 适用于需要获取 API 响应数据的场景
- Wait=false: 适用于只需要触发 API 调用,不关心响应的场景(如发送通知)
- 异步调用(Wait=false)可以提高流程执行效率,但无法获取响应数据
Authorization
说明: 授权信息,用于 API 请求的身份验证。通常是 Bearer Token 或其他认证令牌。
取值范围: 字符串,格式取决于 API 的认证方式
注意事项:
- 如果 API 需要认证,必须提供正确的授权信息
- 可以从流程上下文中动态获取 Token
- 支持多种认证方式(Bearer、Basic、ApiKey 等)
Response
说明: 返回响应参数配置,定义如何从 API 响应中提取数据并写入流程上下文。
配置结构: HttpParameterModels<HttpResponseParameterModel>
响应参数模型:
- ParameterName: 响应数据中的字段路径(支持点号分隔的嵌套路径)
- WriteParameterName: 写入流程上下文的键名
- Description: 参数描述
- DataType: 数据类型(String、Int、Bool、DateTime 等)
注意事项:
- 支持从 JSON 响应中提取嵌套字段(如 "data.user.name")
- 如果响应是数组,会自动取第一个元素
- 数据类型转换失败时会记录错误日志
Action
说明: 执行时机,继承自 ActionActivity。决定 API 调用在流程生命周期的哪个阶段执行。
取值范围:
- QueryEnter: 查询进入时
- Enter: 进入时
- Execute: 执行时(默认)
- QueryExit: 查询退出时
- Exit: 退出时
注意事项:
- 大多数情况使用默认值 Execute
- 如果需要在进入节点前调用 API,使用 QueryEnter 或 Enter
流程上下文
输入参数
| 参数名 | 类型 | 说明 |
|---|---|---|
| ApiId | string | 可以从流程上下文动态获取 API 编号 |
| Authorization | string | 可以从流程上下文动态获取授权信息 |
| API 请求参数 | any | API 配置中定义的请求参数 |
输出参数
| 参数名 | 类型 | 说明 |
|---|---|---|
| {节点名}_StatusCode | int | API 响应的 HTTP 状态码 |
| {节点名}_Response | object | API 响应的完整内容(JSON 字符串) |
| 自定义参数 | any | Response 配置中定义的提取字段 |
数据流转说明
-
请求前:
- 从流程上下文读取 API 请求参数
- 准备授权信息
-
API 调用:
- 通过 IInternalApi 服务调用 API
- 等待响应(如果 Wait=true)
-
响应处理:
- 将 HTTP 状态码写入
{节点名}_StatusCode(节点名为节点的 Name 属性值) - 将完整响应写入
{节点名}_Response - 根据 Response 配置提取字段并写入流程上下文
- 将 HTTP 状态码写入
业务逻辑说明
处理流程
ApiCallActivity 的执行流程如下:
-
初始化:
- 设置默认状态码为 200(OK)
- 获取 IInternalApi 服务
- 记录 API 调用参数日志
-
调用 API:
- 创建 InvokeRequest 对象,设置 ApiID
- 调用
internalApi.CallApiAsync方法 - 传递 Authorization 信息
-
等待响应(如果 Wait=true):
- 等待 API 调用完成
- 获取响应结果(ClientModeAPIHandleResult)
- 记录 API URL 和响应内容日志
-
处理响应:
- 将状态码写入流程上下文
- 将完整响应写入流程上下文
- 解析 JSON 响应(如果配置了 Response 参数)
-
提取字段:
- 遍历 Response 配置中的参数
- 使用点号分隔的路径提取嵌套字段
- 进行数据类型转换
- 将提取的值写入流程上下文
-
异常处理:
- 捕获 HttpRequestException 异常
- 提取 HTTP 状态码
- 记录错误日志
流程图
[准备参数]
↓
[调用 IInternalApi]
↓
[发送 HTTP 请求]
↓
[等待响应] (如果 Wait=true)
↓
[解析 JSON 响应]
↓
[提取字段]
↓
[写入流程上下文]
↓
[继续执行]
JSON 响应解析
ApiCallActivity 支持从 JSON 响应中提取嵌套字段:
示例响应:
{
"code": 200,
"message": "success",
"data": {
"user": {
"id": 1001,
"name": "张三",
"email": "zhangsan@example.com"
},
"products": [
{
"id": "P001",
"name": "产品A"
}
]
}
}
字段提取配置:
code→ 提取根级别字段data.user.name→ 提取嵌套字段data.products→ 提取数组(会取第一个元素)
依赖服务
| 服务接口 | 用途 | 说明 |
|---|---|---|
| IInternalApi | API 调用服务 | 负责实际的 HTTP 请求和响应处理 |
| Flow.ServiceProvider | 服务提供者 | 获取依赖注入的服务 |
| Flow.Logger | 日志记录器 | 记录 API 调用日志 |
异常处理
| 异常类型 | 处理方式 | 说明 |
|---|---|---|
| HttpRequestException | 记录错误日志,设置状态码 | HTTP 请求失败 |
| ApiResponseStatusException | 记录错误日志,设置状态码 | API 返回错误状态码 |
| JSON 解析异常 | 忽略,不处理 | 响应不是 JSON 格式 |
异常处理机制:
- HTTP 异常会被捕获,状态码会写入流程上下文
- JSON 解析失败不会中断流程,只是不提取字段
- 可以通过检查状态码判断 API 调用是否成功
日志记录
ApiCallActivity 记录以下关键日志:
- 调用前:
ApiId={ApiId},Wait={Wait} - 调用后:
ApiId={ApiId},Url={result.Url} - 响应内容:
ApiId={ApiId},Result={result.ResponseBody} - 状态码:
ApiId={ApiId},StatusCode={statusCode} - 异常: 完整的异常堆栈信息
使用示例
基本示例
{
"Type": "ApiCallActivity",
"Name": "查询产品信息",
"Alias": "QueryProduct",
"ApiId": "GetProductInfo",
"Wait": true,
"Action": "Execute"
}
高级示例:提取响应字段
{
"Type": "ApiCallActivity",
"Name": "查询用户信息",
"Alias": "QueryUser",
"ApiId": "GetUserInfo",
"Wait": true,
"Authorization": "Bearer {AccessToken}",
"Response": [
{
"ParameterName": "data.user.id",
"WriteParameterName": "UserId_Value",
"Description": "用户ID",
"DataType": "Int"
},
{
"ParameterName": "data.user.name",
"WriteParameterName": "UserName_Value",
"Description": "用户名称",
"DataType": "String"
},
{
"ParameterName": "data.user.email",
"WriteParameterName": "UserEmail_Value",
"Description": "用户邮箱",
"DataType": "String"
}
]
}
完整流程示例:串联多个 API 调用
{
"Name": "订单处理流程",
"Activities": [
{
"Type": "BusinessActivity",
"Name": "准备订单号",
"Alias": "PrepareOrderNo"
},
{
"Type": "ApiCallActivity",
"Name": "查询订单信息",
"Alias": "QueryOrder",
"ApiId": "GetOrderInfo",
"Wait": true,
"Response": [
{
"ParameterName": "data.customerId",
"WriteParameterName": "CustomerId_Value",
"DataType": "Int"
},
{
"ParameterName": "data.productId",
"WriteParameterName": "ProductId_Value",
"DataType": "String"
}
]
},
{
"Type": "ApiCallActivity",
"Name": "查询客户信息",
"Alias": "QueryCustomer",
"ApiId": "GetCustomerInfo",
"Wait": true,
"Response": [
{
"ParameterName": "data.customerName",
"WriteParameterName": "CustomerName_Value",
"DataType": "String"
},
{
"ParameterName": "data.address",
"WriteParameterName": "CustomerAddress_Value",
"DataType": "String"
}
]
},
{
"Type": "ApiCallActivity",
"Name": "查询产品信息",
"Alias": "QueryProduct",
"ApiId": "GetProductInfo",
"Wait": true,
"Response": [
{
"ParameterName": "data.productName",
"WriteParameterName": "ProductName_Value",
"DataType": "String"
},
{
"ParameterName": "data.price",
"WriteParameterName": "ProductPrice_Value",
"DataType": "Decimal"
}
]
},
{
"Type": "BusinessActivity",
"Name": "处理订单",
"Alias": "ProcessOrder"
}
]
}
异步调用示例
{
"Type": "ApiCallActivity",
"Name": "发送通知",
"Alias": "SendNotification",
"ApiId": "SendEmail",
"Wait": false,
"Action": "Exit"
}
处理 API 响应示例
// 在后续节点中检查 API 调用结果
[Serializable]
[Design("处理API响应", "检查API调用结果并处理", Sort = 1)]
[Category("自定义")]
public class ProcessApiResponseActivity : BusinessActivity
{
public override async Task ProcessAsync(ProcessflowEventArgs args)
{
// 获取状态码
var statusCode = (int)Flow.DataItems["QueryProduct_StatusCode"];
if (statusCode == 200)
{
// API 调用成功,处理响应数据
var productName = Flow.DataItems["ProductName_Value"]?.ToString();
var productPrice = Flow.DataItems["ProductPrice_Value"];
Flow.Logger.LogMessage($"产品信息: {productName}, 价格: {productPrice}", Name);
// 继续业务处理
Flow.DataItems["ProcessResult_Value"] = "Success";
}
else
{
// API 调用失败,记录错误
var response = Flow.DataItems["QueryProduct_Response"]?.ToString();
Flow.Logger.LogErrorMessage($"API调用失败: StatusCode={statusCode}, Response={response}");
Flow.DataItems["ProcessResult_Value"] = "Failed";
throw new BusinessException(Name, $"API调用失败: {statusCode}");
}
await base.ProcessAsync(args);
}
}
扩展开发指南
继承层次
Activity (SYC.Flow.Kernel)
└── BusinessActivity
└── ActionActivity
└── ApiCallActivity
可重写方法
| 方法名 | 用途 | 何时重写 |
|---|---|---|
| ExecuteActionAsync | 执行 API 调用 | 需要自定义 API 调用逻辑 |
| ProcessAsync | 核心业务逻辑 | 需要在 API 调用前后添加处理 |
自定义 API 调用节点示例
[Serializable]
[Design("增强API调用", "带重试和超时的API调用节点", Sort = 1)]
[Category("自定义")]
public class EnhancedApiCallActivity : ApiCallActivity
{
[Design("重试次数", "API调用失败时的重试次数", Sort = 10)]
[Category("API配置")]
[DataMember]
public int RetryCount { get; set; } = 3;
[Design("超时时间", "API调用超时时间(秒)", Sort = 11)]
[Category("API配置")]
[DataMember]
public int TimeoutSeconds { get; set; } = 30;
protected override async Task ExecuteActionAsync(ProcessflowEventArgs args)
{
int attempt = 0;
Exception lastException = null;
while (attempt < RetryCount)
{
attempt++;
try
{
Flow.Logger.LogMessage($"API调用尝试 {attempt}/{RetryCount}", Name);
// 设置超时
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(TimeoutSeconds));
// 调用基类方法
await base.ExecuteActionAsync(args);
// 检查状态码
var statusCode = (int)Flow.DataItems[$"{Name}_StatusCode"];
if (statusCode >= 200 && statusCode < 300)
{
Flow.Logger.LogMessage($"API调用成功: StatusCode={statusCode}", Name);
return; // 成功,退出
}
Flow.Logger.LogWarningMessage($"API返回错误状态码: {statusCode}", Name);
lastException = new Exception($"API返回错误状态码: {statusCode}");
}
catch (OperationCanceledException)
{
Flow.Logger.LogWarningMessage($"API调用超时: {TimeoutSeconds}秒", Name);
lastException = new Exception($"API调用超时: {TimeoutSeconds}秒");
}
catch (Exception ex)
{
Flow.Logger.LogExceptionMessage(ex, Name);
lastException = ex;
}
if (attempt < RetryCount)
{
// 等待后重试
var delay = attempt * 1000; // 递增延迟
Flow.Logger.LogMessage($"等待 {delay}ms 后重试", Name);
await Task.Delay(delay);
}
}
// 所有重试都失败
throw new BusinessException(Name, $"API调用失败,已重试 {RetryCount} 次", lastException);
}
}
注册和集成
-
编译节点:
- 继承 ApiCallActivity 类
- 添加 Design 和 Category 特性
- 编译为 DLL
-
部署节点:
- 将 DLL 放到 LMES 的插件目录
- 重启 LMES 服务
-
配置 API:
- 在系统互联模块中配置 API 接口
- 设置 API 的 URL、请求方法、参数等
-
使用节点:
- 在流程设计器中选择 API 调用节点
- 配置 ApiId 和响应参数
- 连接到流程中
注意事项
- API 配置: 必须先在系统互联模块中配置 API,才能在流程中使用
- 状态码检查: 调用后应检查状态码,确保 API 调用成功
- 异步调用: Wait=false 时无法获取响应数据,只适用于触发类操作
- JSON 格式: Response 参数提取仅支持 JSON 格式的响应
- 授权信息: 如果 API 需要认证,必须提供正确的 Authorization
- 超时处理: 长时间运行的 API 可能导致流程阻塞,建议设置超时
- 异常处理: API 调用失败不会中断流程,需要检查状态码
- 开发建议:
- 在 API 调用后检查状态码,处理失败情况
- 使用 Response 配置提取所需字段,避免手动解析 JSON
- 为 API 调用添加日志,便于问题排查
- 考虑使用重试机制,提高调用成功率
- 敏感信息(如 Token)应从配置或流程上下文动态获取
- 合理使用 Wait 参数,平衡性能和数据需求
相关节点
- ActionActivity: API 调用节点的基类
- ApiConnectActivity: API 连接测试节点
- MethodCallActivity: C# 方法调用节点
- ScriptCallActivity: 脚本调用节点
常见问题
Q1: 如何配置 API 接口?
A: 在系统互联模块中配置:
- 进入系统互联管理界面
- 创建新的 API 配置
- 设置 API 的 URL、请求方法、请求头、请求参数等
- 保存并启用 API
- 记录 API 编号,在流程中使用
Q2: 如何从 API 响应中提取嵌套字段?
A: 使用点号分隔的路径:
{
"Response": [
{
"ParameterName": "data.user.name",
"WriteParameterName": "UserName_Value"
}
]
}
这会从响应的 data.user.name 路径提取值。
Q3: 如何处理 API 调用失败?
A: 在后续节点中检查状态码:
var statusCode = (int)Flow.DataItems["ApiNode_StatusCode"];
if (statusCode != 200)
{
// 处理失败情况
throw new BusinessException("API调用失败");
}
Q4: 如何传递动态参数给 API?
A: API 的请求参数在系统互联中配置,可以引用流程上下文的值:
- 在 API 配置中,参数值使用
{ParameterName}格式 - 流程会自动从流程上下文中获取对应的值
Q5: Wait=false 时如何知道 API 是否调用成功?
A: Wait=false 时无法获取响应,也无法知道调用结果。这种模式只适用于:
- 发送通知类操作(不关心结果)
- 触发异步任务(结果通过其他方式获取)
如果需要知道调用结果,必须使用 Wait=true。
Q6: 如何处理 API 返回的数组数据?
A: ApiCallActivity 会自动取数组的第一个元素。如果需要处理整个数组,应该:
- 不配置 Response 参数
- 在后续节点中手动解析
{节点名}_Response(节点名为节点的 Name 属性值)中的 JSON 数据
Q7: 如何添加自定义请求头?
A: 在系统互联的 API 配置中添加请求头,不是在流程节点中配置。
更新历史
| 日期 | 版本 | 说明 |
|---|---|---|
| 2025-11-28 | 1.0 | 初始版本 |
本文档最后更新时间: 2025-11-28