woocommerce支付插件之一个插件如何撑起 15+ 支付方式
Antom 支付网关核心架构解析:一套代码如何撑起 15+ 支付方式
做电商开发的都知道,支付集成是个体力活。每接一个新的支付渠道,就要写一套网关代码,重复造轮子不说,维护起来更是噩梦。
今天聊聊 Antom 支付网关的设计思路。他们用一个通用基类搞定了支付宝、信用卡、GCash、DANA、Boost 等十几种支付方式,代码复用率相当高。这套架构是怎么设计的?咱们拆开来看。

架构设计的核心思路
Antom 的解决方案很直接:抽象共性,隔离差异。
所有支付方式都有相似的流程:用户下单 → 构造支付请求 → 调用支付 API → 处理异步通知 → 更新订单状态。差异点主要在于支付方法类型、支持的币种、前端展示方式这些配置项。
所以他们设计了一个抽象基类 WC_Gateway_Antom_Common,把通用逻辑全部封装进去。具体支付方式只需要继承这个基类,设置自己的唯一标识,剩下的都交给父类处理。
来看下类继承关系:
// 所有电子钱包都继承同一个基类
class WC_Gateway_Antom_DANA extends WC_Gateway_Antom_Common{
public $id = 'antom_dana';
}
class WC_Gateway_Antom_GCash extends WC_Gateway_Antom_Common{
public $id = 'antom_gcash';
}
class WC_Gateway_Antom_Boost extends WC_Gateway_Antom_Common{
public $id = 'antom_boost';
}
就这么简单。每个子类只需要定义自己的 ID,支付流程、通知处理、状态管理全部复用基类实现。
支付流程的完整链路
当用户在 WooCommerce 结账页提交订单时,核心流程是这样的:

1. 支付请求初始化
process_payment() 方法是整个流程的入口。这里做了几件关键的事:
publicfunction process_payment( $order_id) {
$order = wc_get_order( $order_id );
// 1. 加载核心配置
$core_settings = antom_get_core_settings();
$client_id = $core_settings['clientid'];
$private_key = $core_settings['private_key'];
$test_mode = $core_settings['test_mode'];
// 2. 根据模式选择 API 端点
$api_host = Antom_Payment_Gateways_Statement::ANTOM_ALIPAY_API_HOST;
$path = $test_mode ?
Antom_Payment_Gateways_Statement::ANTOM_ALIPAY_SANDBOX_PATH :
Antom_Payment_Gateways_Statement::ANTOM_ALIPAY_PATH;
// 3. 检查结算币种(生产环境必须设置)
if ( ! $test_mode && ! $core_settings['settlement_currency'] ) {
return $this->return_failure( '结算币种未设置' );
}
// ... 构造支付请求
}
这段代码体现了几个设计细节:
-
• 配置集中管理:通过 antom_get_core_settings()统一读取,避免散落在各处 -
• 沙箱/生产自动切换:根据 test_mode自动选择 API 端点,开发和上线无缝切换 -
• 前置校验:结算币种这种关键配置,在发起请求前就检查,而不是等 API 报错
2. 订单模型组装
支付请求需要携带订单信息、金额、支付方法、环境参数等。Antom 用了一组模型类来结构化这些数据:
// 构造金额模型
$total_amount = intval( antom_order_amount_value_to_decimal( $total, $currency ) );
$amount_model = new Antom_Order_Amount_Model();
$amount_model->set_currency( $currency );
$amount_model->set_value( $total_amount );
// 构造订单模型
$order_model = new Antom_Order_Model();
$order_model->set_order_amount( $amount_model->toArray() );
$order_model->set_reference_order_id( $order_id );
$order_model->set_order_description( 'order info' );
// 构造支付方法模型
$payment_method_model = new Antom_Order_Payment_Method_Model();
$payment_method_model->set_payment_method_type( $payment_method_type );
这种模型化的设计有几个好处:
-
• 类型安全:不用裸数组传参,IDE 能提示,减少手误 -
• 结构清晰:每个模型职责单一,金额就是金额,订单就是订单 -
• 易于扩展:加字段改模型就行,不用动核心逻辑
3. 支付请求检查器
这里有个很有意思的设计——Antom_Payment_Request_Checker。它负责管理支付请求的生命周期,防止重复支付和并发问题。
$payment_request_checker = new Antom_Payment_Request_Checker( $order );
$payment_request_checker->load_all_payment_request_ids();
// 检查是否已有成功支付的记录
if ( $payment_request_checker->has_successful_payment_request_id() ) {
return array(
'result' => 'success',
'redirect' => $order->get_view_order_url(),
);
}
// 检查并发支付请求数量是否超限(默认最多 20 个)
if ( $payment_request_checker->payment_request_ids_number_is_limit() ) {
return $this->return_failure( '支付尝试次数已达上限' );
}
// 获取或生成支付请求 ID
$payment_request_id_info = $payment_request_checker->get_intermediate_payment_request_id_info();
这个检查器解决了几个实际场景的问题:
-
• 用户重复点击支付按钮:生成唯一的 payment_request_id,同一订单多次点击不会重复扣款 -
• 页面刷新后重新支付:复用已有的支付请求 ID,避免创建新订单 -
• 并发控制:限制同时进行的支付请求数量,防止资源耗尽
异步通知处理机制
支付完成后,第三方支付平台会异步通知商户服务器。Antom 的处理逻辑在 payment_notify_handler() 方法里:
publicfunction payment_notify_handler() {
// 1. 获取请求头和请求体
$headers = getallheaders();
$body = file_get_contents( 'php://input' );
// 2. 提取关键字段
$client_id = $headers['Client-Id'] ?? '';
$signature = $headers['Signature'] ?? '';
$request_time = $headers['Request-Time'] ?? '';
// 3. 验证签名(防止伪造通知)
$verify_result = Antom_Signature_Tool::verify(
'POST',
'/wc-api/antom_payment_notify',
$client_id,
$request_time,
$body,
$signature,
$alipay_public_key
);
if ( ! $verify_result ) {
wp_die( '签名验证失败' );
}
// 4. 解析通知内容
$notify_data = json_decode( $body, true );
$notify_type = $notify_data['notifyType']; // PAYMENT_RESULT / CAPTURE_RESULT
$payment_request_id = $notify_data['paymentRequestId'];
// 5. 查找对应订单并更新状态
$order = $this->get_order_by_payment_request_id( $payment_request_id );
// ... 更新订单状态
}
通知处理有几个关键点:
签名验证是第一道防线。任何人都可以往你的回调地址发请求,必须通过 RSA 公钥验证签名,确认消息确实来自支付平台。
幂等处理防止重复更新。同一笔支付可能多次通知,需要根据订单当前状态判断是否需要处理。已完成的订单直接返回成功,不做重复操作。
快速响应。异步通知要求尽快返回,不要在这里做耗时操作。订单状态更新、邮件通知这些可以丢给后台任务。
数字签名工具类
签名是支付安全的基石。Antom 的 Antom_Signature_Tool 工具类封装了 RSA-SHA256 的签名和验签逻辑:
class Antom_Signature_Tool{
// 生成请求签名
public staticfunction sign( $httpMethod, $path, $clientId, $reqTime, $content, $merchantPrivateKey) {
// 构造签名内容:方法 + 路径 + clientId + 时间戳 + 请求体
$signContent = self::genSignContent( $httpMethod, $path, $clientId, $reqTime, $content );
// 使用商户私钥签名
$signValue = self::signWithSHA256RSA( $signContent, $merchantPrivateKey );
return urlencode( $signValue );
}
// 验证响应签名
public staticfunction verify( $httpMethod, $path, $clientId, $rspTime, $rspBody, $signature, $alipayPublicKey) {
$rspContent = self::genSignContent( $httpMethod, $path, $clientId, $rspTime, $rspBody );
return self::verifySignatureWithSHA256RSA( $rspContent, $signature, $alipayPublicKey );
}
private staticfunction genSignContent( $httpMethod, $path, $clientId, $timeString, $content) {
// 格式:GET /ams/api/v1/payments/pay\nclientId.2024-01-01T00:00:00+08:00.{json}
return $httpMethod . ' ' . $path . "\n" . $clientId . '.' . $timeString . '.' . $content;
}
}
签名内容的构造很有讲究。它不是简单地把参数拼接,而是按照固定格式:
HTTP_METHOD PATH\nClientId.RequestTime.RequestBody
这种格式保证了签名的唯一性和不可篡改性。哪怕只改一个字符,签名就会对不上。
配置管理与币种支持
Antom 把支付方式的配置集中管理,通过 antom_get_payment_methods() 函数统一返回:
function antom_get_payment_methods() {
return array(
'antom_alipay_cn' => array(
'slug' => 'antom_alipay_cn',
'payment_method_type' => 'ALIPAY_CN',
'support_currencies' => array( 'CNY', 'USD', 'HKD', 'SGD' ),
'icon' => array( 'alipay-icon.svg' ),
),
'antom_card' => array(
'slug' => 'antom_card',
'payment_method_type' => 'CARD',
'support_currencies' => array( 'USD', 'EUR', 'GBP', 'JPY', 'AUD' ),
),
// ... 其他支付方式
);
}
网关基类在初始化时会读取这些配置,自动设置支持的币种、图标、显示名称等:
protectedfunction setup_props() {
$this->icon = $this->get_pay_setting( 'icon' );
$this->currency = $this->get_pay_setting( 'support_currencies' );
$this->title = $this->get_option( 'title' ) ?: $this->get_pay_setting( 'default_display_name' );
// 后台显示支持的币种列表
$show_currency = array_slice( $this->currency, 0, 4 );
if ( count( $this->currency ) > 4 ) {
$show_currency[] = ' and others';
}
$this->method_description = '支持币种: ' . implode( ' ', $show_currency );
}
总结
Antom 支付网关的架构设计有几个值得借鉴的点:
抽象基类 + 具体实现:把通用逻辑下沉到基类,子类只关注差异点,代码复用率高
模型化数据:用对象代替数组,结构清晰,类型安全
状态机管理:支付请求检查器控制并发和重复,保证数据一致性
安全第一:签名验证贯穿请求和响应,防止中间人攻击和伪造通知
这套架构支撑了 15+ 支付方式的接入,新增一个钱包只需要几行代码。对于需要接入多渠道支付的项目,这种设计思路很有参考价值。
夜雨聆风
