简介
本技术文档面向 DouPHP 的支付宝支付插件,覆盖 PC 网页支付、手机网站支付、当面付三大场景。文档从系统架构、组件职责、数据流、签名验签、加密解密、订单创建到异步通知、同步回调、主动对账等全流程进行说明,并提供测试与生产环境部署建议。所有实现均基于仓库内提供的 Provider/Service 与 SDK 封装,不引入外部未声明依赖。
项目结构
DouPHP 将三种支付宝支付方式以独立插件形式组织,每个插件包含:
- Provider:对外暴露统一接口(start/notify/finish/query),对接框架支付管线
- Service:业务编排,负责构建请求、调用 SDK、处理回调与状态推进
- manifest:插件元信息,注册 Provider
- sdk:各场景对应的支付宝 SDK 与 Builder/Service 类
graph TB
subgraph "PC网页支付"
A_Provider["AlipayProvider"] --> A_Service["AlipayService"]
A_Service --> A_SDK["pagepay SDK<br/>AlipayTradeService / Builder"]
end
subgraph "手机网站支付"
W_Provider["AlipaywapProvider"] --> W_Service["AlipaywapService"]
W_Service --> W_SDK["wappay SDK<br/>AlipayTradeService / Builder"]
end
subgraph "当面付"
F_Provider["Alipayf2fProvider"] --> F_Service["Alipayf2fService"]
F_Service --> F_SDK["f2fpay SDK<br/>AlipayTradeService / Builder"]
end
A_Service --> PaySvc["PaymentService(框架)"]
W_Service --> PaySvc
F_Service --> PaySvc
图示来源
- plugin/alipay/AlipayProvider.php:18-110
- plugin/alipay/AlipayService.php:44-192
- plugin/alipaywap/AlipaywapProvider.php:18-110
- plugin/alipaywap/AlipaywapService.php:45-203
- plugin/alipayf2f/Alipayf2fProvider.php:19-122
- plugin/alipayf2f/Alipayf2fService.php:45-313
核心组件
- Provider 层
- 统一对外方法:start(发起支付)、notify(异步通知)、finish(同步回调)、query(主动对账)
- 提供插件元信息与配置项定义(APPID、应用私钥、支付宝公钥)
- Service 层
- 组装 SDK 配置(网关地址、字符集、签名算法 RSA2、回调地址)
- 使用对应场景的 Builder 构造业务参数并调用 AlipayTradeService
- 校验回调签名后,通过 PaymentService::markSucceeded 推进支付状态机
- 查询交易状态并映射为 succeeded/pending/closed/notFound
- SDK 层
- pagepay/wappay/f2fpay 三类 SDK,分别对应 PC 网页、手机网站、当面付
- 统一入口 AopSdk.php 初始化自动加载与缓存目录
架构总览
整体流程由“前端下单 -> 选择支付宝 -> 插件发起支付 -> 支付宝页面/扫码 -> 异步通知/同步回调 -> 本地状态更新”构成。三个插件共享同一套 Provider/Service 模式,差异仅在 SDK 子模块与交互方式(跳转 vs 二维码轮询)。
sequenceDiagram
participant U as "用户浏览器"
participant P as "插件Provider"
participant S as "插件Service"
participant SDK as "支付宝SDK"
participant PS as "PaymentService(框架)"
participant ALI as "支付宝网关"
U->>P : 发起支付(start)
P->>S : start(request)
S->>SDK : 构建Builder并调用pagePay/wapPay/qrPay
SDK->>ALI : 生成支付链接或二维码
ALI-->>U : 展示支付页/二维码
Note over U,ALI : 用户完成支付
ALI-->>S : 异步通知(notify)
S->>S : 验签(RSA2)
S->>PS : markSucceeded(paymentSn, tradeNo, raw)
PS-->>S : 成功
U->>S : 同步回调(finish)
S->>S : 验签(RSA2)
S->>PS : markSucceeded(...)
S-->>U : 返回订单页
图示来源
- plugin/alipay/AlipayService.php:44-120
- plugin/alipaywap/AlipaywapService.php:45-128
- plugin/alipayf2f/Alipayf2fService.php:45-195
详细组件分析
PC 网页支付(alipay)
- 启动支付:构造 AlipayTradePagePayContentBuilder,设置订单号、金额、标题,调用 AlipayTradeService.pagePay 返回支付表单/链接
- 异步通知:使用 SDK 的 check 方法进行签名校验,通过后提取 out_trade_no 与 trade_no,调用 PaymentService::markSucceeded
- 同步回调:同样验签成功后推进状态,并发送邮件通知站点管理员
- 主动对账:使用 AlipayTradeQueryContentBuilder 查询交易状态,按 code/trade_status 映射为 succeeded/pending/closed/notFound
flowchart TD
Start(["开始"]) --> Build["构建页面支付请求<br/>setOutTradeNo/setTotalAmount/setSubject"]
Build --> CallPay["调用 pagePay<br/>返回支付表单/链接"]
CallPay --> Notify{"收到异步通知?"}
Notify -- 是 --> Verify["验签(check)"]
Verify --> Valid{"验签通过?"}
Valid -- 否 --> Fail["返回 fail"]
Valid -- 是 --> Mark["markSucceeded(paymentSn, tradeNo, raw)"]
Mark --> End(["结束"])
Notify -- 否 --> Finish{"收到同步回调?"}
Finish -- 是 --> Verify2["验签(check)"]
Verify2 --> Valid2{"验签通过?"}
Valid2 -- 否 --> Redirect["重定向至订单列表"]
Valid2 -- 是 --> Mark2["markSucceeded(...)"]
Mark2 --> Redirect
Finish -- 否 --> Query["主动对账(query)"]
Query --> Map["映射trade_status<br/>succeeded/pending/closed/notFound"]
Map --> End
图示来源
- plugin/alipay/AlipayService.php:44-192
手机网站支付(alipaywap)
- 启动支付:构造 AlipayTradeWapPayContentBuilder,设置超时时间、金额、订单号,调用 wapPay 输出支付页面
- 异步通知与同步回调:与 PC 网页支付一致,使用 SDK 验签后推进状态
- 主动对账:复用 query 逻辑,按相同规则映射结果
sequenceDiagram
participant U as "用户移动端"
participant WProv as "AlipaywapProvider"
participant WSvc as "AlipaywapService"
participant WSDK as "wappay SDK"
participant ALI as "支付宝网关"
U->>WProv : start
WProv->>WSvc : start(request)
WSvc->>WSDK : wapPay(builder, return_url, notify_url)
WSDK-->>U : 打开手机支付页
ALI-->>WSvc : notify(异步)
WSvc->>WSvc : check(data)
WSvc->>WSvc : markSucceeded(...)
U->>WSvc : finish(同步)
WSvc->>WSvc : check(data)
WSvc->>WSvc : markSucceeded(...)
图示来源
- plugin/alipaywap/AlipaywapService.php:45-128
当面付(alipayf2f)
- 启动支付:构造 AlipayTradePrecreateContentBuilder,调用 qrPay 获取二维码内容;页面渲染二维码并定时轮询 status 接口
- 异步通知:使用 AopClient 的 rsaCheckV1 进行签名校验,成功后推进状态
- 同步回调:使用 f2fpay SDK 的 check 验签后推进状态
- 主动对账与轮询:status() 在扫码期间轮询查询交易结果;query() 用于后台对账任务
sequenceDiagram
participant U as "用户"
participant FProv as "Alipayf2fProvider"
participant FSvc as "Alipayf2fService"
participant FSDK as "f2fpay SDK"
participant QRC as "二维码页面"
participant ALI as "支付宝网关"
U->>FProv : start
FProv->>FSvc : start(request)
FSvc->>FSDK : qrPay(builder)
FSDK-->>FSvc : 返回qr_code
FSvc-->>QRC : 渲染二维码+JS轮询status
U->>AL : 扫码支付
ALI-->>FSvc : notify(异步)
FSvc->>FSvc : rsaCheckV1(data)
FSvc->>FSvc : markSucceeded(...)
QRC->>FSvc : POST status(out_trade_no)
FSvc->>FSDK : queryTradeResult(builder)
FSDK-->>FSvc : SUCCESS?
alt 已支付
FSvc->>FSvc : markSucceeded(...)
FSvc-->>QRC : SUCCESS
else 未支付
FSvc-->>QRC : FAIL
end
图示来源
- plugin/alipayf2f/Alipayf2fService.php:45-195
- plugin/alipayf2f/Alipayf2fService.php:257-292
依赖关系分析
- 插件与框架
- Provider 实现框架定义的支付提供者接口,统一接入 start/notify/finish/query
- Service 依赖框架的 PaymentService 推进状态机,并通过 DB/Mail 等能力完成后续动作
- 插件内部依赖
- 每个 Service 通过 require_once 动态加载对应 SDK 的 service 与 builder 类
- 配置读取通过 plugin()->getWithConfig 获取 APPID、私钥、公钥及回调地址
- 外部依赖
- 支付宝开放平台网关 https://openapi.alipay.com/gateway.do
- 签名算法 RSA2,字符集 UTF-8
graph LR
Prov["Provider"] --> Svc["Service"]
Svc --> SDK["AlipayTradeService / Builder"]
Svc --> PaySvc["PaymentService(框架)"]
Svc --> Cfg["plugin()->getWithConfig('xxx')"]
SDK --> GW["支付宝网关"]
图示来源
- plugin/alipay/AlipayService.php:177-192
- plugin/alipaywap/AlipaywapService.php:188-203
- plugin/alipayf2f/Alipayf2fService.php:297-313
性能与可靠性
- 异步优先:所有支付结果以支付宝异步通知为准,同步回调仅做用户体验增强
- 幂等性:通过 paymentSn 唯一标识一次支付尝试,重复通知不会导致重复入账
- 主动对账:当异步通知丢失时,可通过 query() 定期拉取交易状态,确保最终一致性
- 错误处理:
- 验签失败直接拒绝处理
- 查询异常捕获并返回 failed,避免影响主流程
- 配置缺失抛出 DomainException,快速失败便于定位
故障排查指南
- 验签失败
- 检查支付宝公钥与应用私钥是否匹配
- 确认 sign_type 为 RSA2,charset 为 UTF-8
- 回调未触发
- 检查 notify_url 与 return_url 是否可被公网访问
- 检查防火墙/反向代理是否放行支付宝回调域名
- 查询结果为 notFound
- 支付宝返回 code=40004 表示未找到该笔交易,需等待或重试
- 日志与调试
- SDK 工作目录默认 /tmp,可在 AopSdk.php 中调整 AOP_SDK_WORK_DIR
- 开发模式 AOP_SDK_DEV_MODE=true 有助于调试
结论
本插件以统一的 Provider/Service 模式实现了 PC 网页支付、手机网站支付与当面付三种场景,借助支付宝官方 SDK 完成签名验签与交易操作,并通过框架 PaymentService 保证状态机的一致性与可追溯性。配合主动对账机制,可有效应对网络抖动与通知丢失等异常情况,满足生产环境的稳定性要求。
附录:配置与部署
配置参数
- 通用参数(三个插件共用)
- app_id:支付宝开放平台应用 APPID
- merchant_private_key:应用私钥(RSA2)
- alipay_public_key:支付宝公钥(RSA2)
- charset:UTF-8
- sign_type:RSA2
- gatewayUrl:https://openapi.alipay.com/gateway.do
- 回调地址(由 Service 自动拼接)
- notify_url:index.php?route=plugin/{插件名}/notify
- return_url:index.php?route=plugin/{插件名}/finish
集成步骤
- 启用插件
- 在管理后台启用对应支付插件,填写 APPID、私钥、公钥
- 配置回调
- 确保 notify_url 与 return_url 可被公网访问且路由正确
- 验证签名
- 使用沙箱环境先验证验签与回调链路
- 上线切换
- 将网关地址与密钥切换至生产环境
测试环境搭建
- 使用支付宝沙箱账号与沙箱网关进行测试
- 开启 AOP_SDK_DEV_MODE=true,便于查看 SDK 缓存与日志
- 使用浏览器模拟 PC/移动端,或使用二维码工具扫描当面付二维码
生产环境部署
- 关闭开发模式 AOP_SDK_DEV_MODE=false,提升性能
- 合理设置 AOP_SDK_WORK_DIR 并确保可写
- 配置防火墙与反向代理,允许支付宝回调域名访问
- 建立对账任务,周期性调用 query() 补齐遗漏通知