跳到主要内容
版本:Next

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 调用,实现复杂的集成场景

配置说明

基本配置

属性名类型必填默认值说明
ApiIdstring-API 编号,调用互联中的 API 接口
Waitbooltrue是否等待执行结束
Authorizationstring-授权信息(请求 Token)
ResponseHttpParameterModels空集合返回响应参数配置
ActionActionTypeExecute执行时机(继承自 ActionActivity)
IsSynchronousbooltrue是否同步执行(继承自 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

流程上下文

输入参数

参数名类型说明
ApiIdstring可以从流程上下文动态获取 API 编号
Authorizationstring可以从流程上下文动态获取授权信息
API 请求参数anyAPI 配置中定义的请求参数

输出参数

参数名类型说明
{节点名}_StatusCodeintAPI 响应的 HTTP 状态码
{节点名}_ResponseobjectAPI 响应的完整内容(JSON 字符串)
自定义参数anyResponse 配置中定义的提取字段

数据流转说明

  1. 请求前:

    • 从流程上下文读取 API 请求参数
    • 准备授权信息
  2. API 调用:

    • 通过 IInternalApi 服务调用 API
    • 等待响应(如果 Wait=true)
  3. 响应处理:

    • 将 HTTP 状态码写入 {节点名}_StatusCode(节点名为节点的 Name 属性值)
    • 将完整响应写入 {节点名}_Response
    • 根据 Response 配置提取字段并写入流程上下文

业务逻辑说明

处理流程

ApiCallActivity 的执行流程如下:

  1. 初始化:

    • 设置默认状态码为 200(OK)
    • 获取 IInternalApi 服务
    • 记录 API 调用参数日志
  2. 调用 API:

    • 创建 InvokeRequest 对象,设置 ApiID
    • 调用 internalApi.CallApiAsync 方法
    • 传递 Authorization 信息
  3. 等待响应(如果 Wait=true):

    • 等待 API 调用完成
    • 获取响应结果(ClientModeAPIHandleResult)
    • 记录 API URL 和响应内容日志
  4. 处理响应:

    • 将状态码写入流程上下文
    • 将完整响应写入流程上下文
    • 解析 JSON 响应(如果配置了 Response 参数)
  5. 提取字段:

    • 遍历 Response 配置中的参数
    • 使用点号分隔的路径提取嵌套字段
    • 进行数据类型转换
    • 将提取的值写入流程上下文
  6. 异常处理:

    • 捕获 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 → 提取数组(会取第一个元素)

依赖服务

服务接口用途说明
IInternalApiAPI 调用服务负责实际的 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);
}
}

注册和集成

  1. 编译节点:

    • 继承 ApiCallActivity 类
    • 添加 Design 和 Category 特性
    • 编译为 DLL
  2. 部署节点:

    • 将 DLL 放到 LMES 的插件目录
    • 重启 LMES 服务
  3. 配置 API:

    • 在系统互联模块中配置 API 接口
    • 设置 API 的 URL、请求方法、参数等
  4. 使用节点:

    • 在流程设计器中选择 API 调用节点
    • 配置 ApiId 和响应参数
    • 连接到流程中

注意事项

  • ⚠️ API 配置: 必须先在系统互联模块中配置 API,才能在流程中使用
  • ⚠️ 状态码检查: 调用后应检查状态码,确保 API 调用成功
  • ⚠️ 异步调用: Wait=false 时无法获取响应数据,只适用于触发类操作
  • ⚠️ JSON 格式: Response 参数提取仅支持 JSON 格式的响应
  • ⚠️ 授权信息: 如果 API 需要认证,必须提供正确的 Authorization
  • ⚠️ 超时处理: 长时间运行的 API 可能导致流程阻塞,建议设置超时
  • ⚠️ 异常处理: API 调用失败不会中断流程,需要检查状态码
  • 💡 最佳实践:
    • 在 API 调用后检查状态码,处理失败情况
    • 使用 Response 配置提取所需字段,避免手动解析 JSON
    • 为 API 调用添加日志,便于问题排查
    • 考虑使用重试机制,提高调用成功率
    • 敏感信息(如 Token)应从配置或流程上下文动态获取
    • 合理使用 Wait 参数,平衡性能和数据需求

相关节点

常见问题

Q1: 如何配置 API 接口?

A: 在系统互联模块中配置:

  1. 进入系统互联管理界面
  2. 创建新的 API 配置
  3. 设置 API 的 URL、请求方法、请求头、请求参数等
  4. 保存并启用 API
  5. 记录 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-281.0初始版本

本文档最后更新时间: 2025-11-28