如何在 WSO2 API Manager 中集成 payment gateway
明确结论
这里的 callback URL 不是支付网关首页,也不是 Developer Portal 的普通页面地址。它是支付完成后接收支付结果的回调端点。
建议采用以下集成流程:
- 用户提交 subscription 后,WSO2 API Manager 创建一个待处理的 workflow,并生成
workflowReferenceId。 - 自定义 workflow executor 将用户重定向到支付网关,同时传递:
- 支付回调地址
callback URL workflowReferenceId- 订单号等业务参数
- 支付回调地址
- 支付网关将支付结果通知支付回调服务。
- 回调服务先向支付网关核验支付结果。
- 确认支付成功后,回调服务调用 WSO2 API Manager 的 workflow callback API,将 workflow 标记为
APPROVED。 - API Manager 随后执行 workflow executor 的
complete(...),完成 subscription。
通常不应让支付网关或浏览器直接调用 Java complete(...) 方法。API Manager 会在处理 workflow callback 时从内部调用该方法。
callback URL 应该指向哪里
建议将它设置为由你控制的服务端地址,例如:
https://billing.example.com/payment/wso2/callback
这个地址负责接收支付网关发来的服务器通知,然后调用 API Manager。
不要把支付网关的浏览器跳转当作可信的支付成功通知。很多支付平台会同时提供两类回调:
return_url:支付完成后,将用户的浏览器跳转到指定页面。notify_url或 webhook:支付平台从服务端向商户系统发送通知。
是否完成 subscription,应以 webhook 通知或主动查询支付结果为准,不能只根据浏览器跳转参数判断支付是否成功。
如果当前 WSO2 版本的文档明确要求将 API Manager 的 workflow callback endpoint 用作 callback URL,还需要确认支付网关能否按照该接口的要求发送 HTTP 方法、JSON 数据和认证信息。多数支付网关无法直接满足这些要求,所以通常需要增加一个支付回调服务。
推荐的处理流程
1. 创建 subscription workflow
自定义 subscription workflow executor 在 execute(...) 阶段发起支付,并让 workflow 保持待处理状态。此时需要保存以下映射关系:
paymentOrderId -> workflowReferenceId
不要只依赖浏览器传递 workflowReferenceId。在服务端保存映射可以避免参数被篡改,也便于处理异步通知和重复回调。
支付请求的结构可以是:
{
"orderId": "PAY-20260831-0001",
"amount": "99.00",
"currency": "CNY",
"returnUrl": "https://portal.example.com/payment/result",
"notifyUrl": "https://billing.example.com/payment/wso2/callback",
"metadata": {
"workflowReferenceId": "8de4b993-xxxx-xxxx-xxxx-87eaf9d2b491"
}
}
具体字段名由支付网关决定。有些网关会使用 additional_parameters、metadata、custom 或 passback_params 等名称。
2. 接收并验证支付通知
回调服务收到通知后,至少要验证以下内容:
- 支付网关签名是否正确;
- 订单号是否存在;
- 订单金额和币种是否匹配;
- 支付状态是否为最终成功状态;
- 该订单是否已经处理;
- 必要时,通过支付网关的订单查询 API 再次确认。
示例逻辑:
@PostMapping("/payment/wso2/callback")
public ResponseEntity<String> handlePaymentCallback(
@RequestBody String requestBody,
@RequestHeader Map<String, String> headers) {
PaymentNotification notification =
paymentGateway.verifyAndParse(requestBody, headers);
if (!notification.isPaymentSuccessful()) {
return ResponseEntity.ok("ignored");
}
PaymentOrder order = paymentOrderRepository
.findByOrderId(notification.getOrderId())
.orElseThrow(() -> new IllegalArgumentException("Unknown order"));
if (!order.matches(notification.getAmount(), notification.getCurrency())) {
throw new IllegalStateException("Payment amount or currency mismatch");
}
if (!order.isWorkflowCompleted()) {
wso2WorkflowClient.approve(order.getWorkflowReferenceId());
order.markWorkflowCompleted();
paymentOrderRepository.save(order);
}
return ResponseEntity.ok("success");
}
这段代码只展示整体结构。支付签名的验证方式、回调返回内容和重试规则,都应以实际使用的支付网关协议为准。
3. 调用 WSO2 workflow callback API
不同版本的 WSO2 API Manager 可能使用不同的 REST API 路径、版本号、认证方式和请求结构,不能把某个固定 URL 当作所有版本都适用的地址。应在当前部署版本的 REST API 文档或 API Console 中确认 workflow endpoint。
常见的调用形式如下:
curl --request POST \
'https://apim.example.com:<port>/<workflow-callback-endpoint>' \
--header 'Authorization: Bearer <access-token>' \
--header 'Content-Type: application/json' \
--data '{
"workflowReferenceId": "8de4b993-xxxx-xxxx-xxxx-87eaf9d2b491",
"workflowStatus": "APPROVED",
"description": "Payment verified"
}'
主要参数是:
{
"workflowReferenceId": "<创建 subscription 时生成的引用 ID>",
"workflowStatus": "APPROVED"
}
有些版本可能使用 status,也可能将接口放在旧版 Store API、DevPortal API 或独立的 workflow callback service 中。具体实现必须以当前版本的 OpenAPI 定义为准,不能只替换示例中的版本号。
如果支付失败、订单关闭或超时,可以根据当前版本支持的状态提交 REJECTED。不要自行猜测状态名称,应先查看该版本允许的 workflow status 枚举。
complete(...) 是怎样被调用的
自定义 Java workflow executor 通常分为两个阶段:
public WorkflowResponse execute(Workflow workflow)
用户提交 subscription 时会执行 execute(...)。该方法用于创建支付订单,并让 workflow 保持待处理状态。
public WorkflowResponse complete(Workflow workflow)
workflow callback API 收到 APPROVED 或 REJECTED 状态后,API Manager 会根据 workflowReferenceId 找到原来的 workflow,再调用对应 executor 的 complete(...)。
正常的调用链如下:
支付成功
-> 支付回调服务验证结果
-> 调用 workflow callback API
-> API Manager 查找 workflow
-> API Manager 调用 complete(...)
-> subscription 被批准
不建议在支付回调代码中直接实例化 executor 并调用:
executor.complete(workflow);
这种做法会绕过 API Manager 的 workflow 持久化、状态检查、事务处理和 executor 定位机制,可能导致 workflow 已经批准,但 subscription 没有正确更新。
complete(...) 的示意实现
自定义 executor 的结构大致如下:
public class PaymentSubscriptionWorkflowExecutor
extends SubscriptionCreationWorkflowExecutor {
@Override
public WorkflowResponse execute(Workflow workflow)
throws WorkflowException {
SubscriptionWorkflowDTO subscriptionWorkflow =
(SubscriptionWorkflowDTO) workflow;
String workflowReferenceId =
subscriptionWorkflow.getExternalWorkflowReference();
String paymentUrl = createPaymentOrder(
workflowReferenceId,
subscriptionWorkflow
);
WorkflowResponse response = new GeneralWorkflowResponse();
response.setWorkflowStatus(WorkflowStatus.CREATED);
response.setRedirectUrl(paymentUrl);
return response;
}
@Override
public WorkflowResponse complete(Workflow workflow)
throws WorkflowException {
return super.complete(workflow);
}
}
这段代码只说明职责如何划分。类名、DTO、状态常量、setRedirectUrl(...) 是否存在,以及父类的具体行为,都取决于所使用的 WSO2 API Manager 版本。实现时应参考目标版本提供的 workflow executor API 和示例代码。
通常应尽量复用 WSO2 自带的 subscription completion 逻辑,例如调用父类的 complete(...)。如果只修改 workflow 状态,可能会漏掉真正的 subscription 状态更新。
回调后跳转到 Developer Portal
workflow callback 是服务端的状态更新接口,不一定负责页面跳转。支付完成后,可以将浏览器跳转到自己的结果页:
https://portal.example.com/payment/result?orderId=PAY-20260831-0001
结果页再通过后端查询:
- 支付订单状态;
- workflow 状态;
- subscription 是否已激活。
不要在 URL 中直接暴露访问令牌,也不要让前端使用高权限凭据调用 WSO2 workflow API。
注意事项
workflowReferenceId必须是创建该 subscription workflow 时生成的值,不能用 subscription ID、application ID 或支付订单号代替。- callback API 通常需要认证。访问令牌和客户端密钥只能保存在服务端。
- 支付网关可能重复发送通知,因此回调处理必须具备幂等性。
- 必须先验证支付,再批准 subscription,否则可能出现用户未付款却可以调用 API 的时间窗口。
- API Manager 无法访问支付回调服务时,应检查反向代理、TLS 证书、防火墙和主机名解析。
- 如果 callback 返回成功,但 subscription 仍处于
ON_HOLD或待审批状态,应检查workflowReferenceId、executor 配置、workflow 状态值和 API Manager 日志。 - 支付成功和 workflow 批准最好通过可重试的状态机处理。如果支付已经成功,但 API Manager 暂时不可用,应保存订单状态并重试 callback,不要要求用户再次付款。
备注:内容仅供参考。
