简介
本文件面向 DouPHP 小程序支付组件,系统梳理微信支付、支付宝支付的实现方式,覆盖下单发起、安全验签、异步回调、主动对账、订单状态同步、退款处理等关键流程。文档同时说明小程序端的支付交互、错误处理机制以及与第三方支付平台的集成要点和安全注意事项。
项目结构
支付能力由“插件层 + 核心服务层 + 小程序前端”三部分构成:
- 插件层:按支付方式拆分(微信 wxpay、支付宝 alipay),提供 Provider 门面与 Service 业务逻辑,封装第三方 SDK。
- 核心服务层:统一支付台账与状态机(PaymentService),负责幂等、订单联动、退款分账等。
- 小程序前端:下单页与订单详情页,调用后端接口完成支付与结果展示。
graph TB
subgraph "小程序端"
M_Checkout["订单结算页<br/>checkout.ts"]
M_Show["订单详情/支付入口<br/>show.ts"]
end
subgraph "后端核心"
P_Svc["PaymentService<br/>统一支付台账/状态机"]
end
subgraph "支付插件"
W_Provider["WxpayProvider<br/>微信支付门面"]
W_Service["WxpayService<br/>JSAPI/NATIVE/H5 发起+回调+轮询"]
A_Provider["AlipayProvider<br/>支付宝门面"]
A_Service["AlipayService<br/>电脑网站支付发起+回调+对账"]
end
M_Checkout --> |创建订单并跳转收银台| P_Svc
M_Show --> |发起支付/查询| P_Svc
P_Svc --> W_Provider
P_Svc --> A_Provider
W_Provider --> W_Service
A_Provider --> A_Service
W_Service --> |异步通知/轮询| P_Svc
A_Service --> |异步通知/对账| P_Svc
核心组件
- 微信支付插件
- Provider:对外暴露 start/notify/finish/status/query 等能力,适配小程序与 H5/PC 场景。
- Service:根据 UA 自动选择 JSAPI/NATIVE/H5;统一 notify 验签;支持 Native 扫码轮询与主动对账。
- 支付宝插件
- Provider:对外暴露 start/notify/finish/query。
- Service:电脑网站支付发起;notify/finish 验签后推进支付成功;query 主动对账。
- 统一支付服务
- PaymentService:维护 payment 行(payment_sn、gateway、amount、status)、订单联动(PAID)、钱包混合支付、退款分账、幂等与事务保障。
架构总览
支付主流程(以微信支付为例):
- 小程序下单:前端 checkout.ts 提交订单信息,后端创建 pending 的 payment,返回收银台或支付参数。
- 发起支付:WxpayService 根据 UA 选择 JSAPI/NATIVE/H5,生成支付参数或二维码。
- 异步通知:微信回调到统一 notify,内部 NotifyCallback 验签并二次查询确认,成功后调用 PaymentService.markSucceeded。
- 轮询兜底:NATIVE 扫码通过 status 轮询查询交易状态,命中 SUCCESS 即推进支付成功。
- 主动对账:定时任务或管理端触发 query,统一映射为 succeeded/pending/closed/notFound。
sequenceDiagram
participant U as "用户"
participant MP as "小程序前端<br/>checkout.ts / show.ts"
participant PS as "PaymentService"
participant WP as "WxpayProvider"
participant WS as "WxpayService"
participant WX as "微信支付网关"
U->>MP : 点击“去支付”
MP->>PS : 创建订单并生成 payment(pending)
PS-->>MP : 返回 payment_sn / 收银台URL
MP->>WP : 发起支付(start)
WP->>WS : 路由到 JSAPI/NATIVE/H5
WS->>WX : 统一下单(含 notify_url)
WX-->>WS : 返回支付参数/二维码
WS-->>MP : 渲染支付按钮/二维码
WX-->>WS : 异步通知(notify)
WS->>WS : 验签 + 二次查询
WS->>PS : markSucceeded(payment_sn, transaction_id)
PS-->>MP : 订单状态变为已支付
详细组件分析
微信支付组件(WxpayProvider / WxpayService)
- 能力边界
- start:按 UA 派发 JSAPI(微信小程序内)、H5(移动端浏览器)、NATIVE(PC 扫码)。
- notify:统一回调入口,SDK 验签 + 二次查询确认,成功后推进支付成功。
- finish:支付完成后回跳订单页。
- status:NATIVE 扫码轮询,按 paymentSn 主动查询微信,命中 SUCCESS 即推进支付成功。
- query:主动对账,将微信返回状态映射为 succeeded/pending/closed/notFound。
- 数据流
- out_trade_no 使用 payment.payment_sn;transaction_id 作为第三方流水号落库。
- 日志写入 storage/log/payment/wxpay/ 下按日切分的日志文件。
- 配置项
- appid、appsecret、mchid、key;证书路径在插件目录下。
flowchart TD
Start(["start()"]) --> UA{"UA 判断"}
UA --> |MicroMessenger| JSAPI["startJsapi()<br/>JSAPI 统一下单"]
UA --> |IS_MOBILE| H5["startH5()<br/>MWEB 统一下单"]
UA --> |其他| NATIVE["startNative()<br/>生成二维码 + 轮询"]
JSAPI --> ReturnJS["返回 JS 参数/按钮"]
H5 --> ReturnH5["返回 mweb_url + 重定向"]
NATIVE --> ReturnQR["返回二维码 + 轮询脚本"]
支付宝组件(AlipayProvider / AlipayService)
- 能力边界
- start:电脑网站支付,构建请求并返回页面跳转链接。
- notify/finish:验签通过后推进支付成功;finish 时尝试发送站内通知邮件。
- query:主动对账,将 trade_status 映射为 succeeded/pending/closed/notFound。
- 数据流
- out_trade_no 使用 payment.payment_sn;trade_no 作为第三方流水号。
- 配置校验失败抛出领域异常,提示管理员补全配置。
sequenceDiagram
participant MP as "小程序前端"
participant AP as "AlipayProvider"
participant AS as "AlipayService"
participant ALI as "支付宝网关"
participant PS as "PaymentService"
MP->>AP : start(PaymentRequest)
AP->>AS : start()
AS->>ALI : 电脑网站支付下单
ALI-->>AS : 返回跳转链接
AS-->>MP : 返回 redirect URL
ALI-->>AS : 异步通知(notify)
AS->>PS : markSucceeded(payment_sn, trade_no)
PS-->>MP : 订单状态更新为已支付
统一支付服务(PaymentService)
- 核心职责
- 创建 payment 记录(pending),生成唯一 payment_sn。
- 标记成功:markSucceeded 幂等推进 payment 与订单状态(PAID),累计网关已付金额。
- 订单收尾:tryFinalizeOrder 汇总各腿金额,达到订单金额则推进 PAID。
- 钱包支付:markSucceededByWallet 扣余额、落账、尝试收尾。
- 退款分账:refundOrder 按渠道优先顺序拆分退款;wallet 立即退回,网关登记 pending 待人工/回调收尾。
- 退款收尾:markRefundSucceeded 将 pending 退款升级为 succeeded,并更新支付腿状态。
- 幂等与一致性
- DB UNIQUE KEY(gateway, transaction_id) 防重复落库。
- changeStatus 事务内执行高风险联动,失败不推进终态,避免不可逆错配。
flowchart TD
In(["收到支付成功事件"]) --> Find["查找 payment 记录"]
Find --> CheckState{"是否已成功?"}
CheckState --> |是| Finalize["tryFinalizeOrder(order_sn)"]
CheckState --> |否| Validate["校验订单可收款状态"]
Validate --> UpdatePay["更新 payment 为 SUCCEEDED"]
UpdatePay --> Accumulate["累计 gateway_paid"]
Accumulate --> Finalize
Finalize --> Done(["结束"])
小程序端支付交互
- 下单与收银台
- checkout.ts:提交收货信息与优惠券后,跳转到 cashier_url(后端生成的支付入口)。
- 订单详情支付
- show.ts:在订单详情页发起微信支付(wx.requestPayment),成功后刷新订单状态。
sequenceDiagram
participant C as "小程序页面"
participant API as "后端接口"
participant PS as "PaymentService"
participant WX as "微信支付"
C->>API : POST order.checkout.checkout_post
API-->>C : 返回 cashier_url
C->>API : POST user.weixin.pay
API->>PS : 创建/获取 payment
PS-->>API : 返回支付参数(timeStamp/nonceStr/package/paySign)
API-->>C : 返回支付参数
C->>WX : wx.requestPayment(...)
WX-->>C : 支付结果
C->>API : 刷新订单(show)
依赖关系分析
- 插件与核心服务解耦:Provider 仅做路由转发,Service 负责具体对接;PaymentService 提供统一状态机与订单联动。
- 外部依赖:
- 微信支付 SDK:WxPayConfig、WxPayApi、WxPayNotify 等。
- 支付宝 SDK:AlipayTradeService、ContentBuilder 系列。
- 耦合点
- 回调中通过 payment_sn 定位支付记录,再调用 PaymentService 推进状态。
- 订单状态推进由 OrderStatusTransition 保证合法性。
graph LR
WProv["WxpayProvider"] --> WSvc["WxpayService"]
AProv["AlipayProvider"] --> ASvc["AlipayService"]
WSvc --> PSvc["PaymentService"]
ASvc --> PSvc
PSvc --> OSt["OrderStatusTransition"]
性能与可靠性
- 幂等性
- 支付成功回调与对账均具备幂等保护,避免重复推进订单。
- 容错与兜底
- 微信 NATIVE 扫码支持轮询;支付宝支持主动对账;PaymentService 支持多次支付腿凑满才收尾。
- 日志与可观测性
- 微信支付日志按日写入 storage/log/payment/wxpay/;回调原文落库便于排查。
- 并发控制
- 钱包支付使用事务与行锁防止超扣;订单状态推进在事务内完成高风险联动。
故障排查指南
- 常见问题
- 配置不完整:支付宝插件会抛出领域异常提示管理员补全;微信支付需确保 appid/mchid/key 及证书路径正确。
- 回调未生效:检查 notify_url 可达性与签名验证;查看日志与 raw_callback。
- 订单未推进:核对订单状态是否允许收款;检查 tryFinalizeOrder 是否满足金额条件。
- 建议步骤
- 查看对应插件日志与数据库 order_payment.raw_callback。
- 使用 query 接口进行主动对账,观察返回状态。
- 若为 NATIVE 扫码,确认 status 轮询是否被前端正确调用。
结论
DouPHP 支付组件通过“插件化 + 统一服务”的架构,实现了微信支付与支付宝的统一接入与可靠交付。核心优势包括:
- 多端适配:JSAPI/NATIVE/H5 自动识别与降级。
- 强一致:基于 PaymentService 的状态机与事务保障,确保订单与支付台账一致。
- 高可用:异步通知 + 轮询 + 主动对账的多重兜底机制。
- 可扩展:新增支付方式只需实现 Provider/Service 并遵循统一 DTO 契约。
附录:配置与安全清单
- 微信支付配置
- 开发者 ID(AppID)、开发者密码(AppSecret)、商户号(MCHID)、API 密钥(KEY)。
- 证书路径:apiclient_cert.pem、apiclient_key.pem。
- 回调地址:统一 notify 路由。
- 支付宝配置
- APPID、应用私钥、支付宝公钥。
- 回调地址:notify_url、return_url。
- 安全要点
- 所有回调必须验签并通过二次查询确认。
- 敏感配置应加密存储,禁止硬编码。
- 对外暴露的回调接口需限制来源与频率,记录原始报文以便审计。
- 退款流程区分 wallet 即时退回与网关 pending 登记,最终由人工/回调收尾。