简介
本技术文档面向 DouPHP 的微信支付插件,覆盖 JSAPI 支付、扫码(Native)支付、H5 支付以及小程序支付的接入方式。文档从系统架构、数据流、处理逻辑、安全机制到调试排错进行系统化说明,帮助开发者快速理解并正确集成微信支付能力。
项目结构
微信支付插件位于 plugin/wxpay 目录下,采用“提供者 + 服务 + SDK”的分层组织:
- 插件清单:声明插件分组与提供类
- 提供者:实现统一支付接口,负责路由到具体支付方式
- 服务:封装统一下单、通知处理、查询、退款等业务流程
- SDK:微信官方示例 SDK,包含配置、API、JSAPI/Native/H5 工具类
- 回调处理器:继承 SDK 的 WxPayNotify,完成验签、二次确认与订单推进
- 二维码生成:用于 PC 端扫码支付展示 code_url
graph TB
A["前端/商户系统"] --> B["WxpayProvider<br/>统一入口"]
B --> C["WxpayService<br/>业务编排"]
C --> D["SDK: WxPay.Api<br/>统一下单/查询"]
C --> E["SDK: JsApiPay/NativePay<br/>JSAPI/Native"]
C --> F["SDK: wechatAppPay<br/>H5(MWEB)"]
C --> G["Internal\\NotifyCallback<br/>异步通知处理"]
G --> H["PaymentService<br/>标记成功/更新订单"]
核心组件
- 插件清单 manifest.php:声明插件组 payment 与提供类 Dou\Plugin\Wxpay\WxpayProvider
- 提供者 WxpayProvider:实现 ReconcilablePaymentProviderInterface 与 PollablePaymentProviderInterface,暴露 start/notify/finish/status/query 等方法
- 服务 WxpayService:按 UA 自动选择 JSAPI/H5/Native;封装统一下单、通知、查询、轮询;构建 SDK 配置与日志
- 通知回调 NotifyCallback:继承 WxPayNotify,重写 Queryorder/NotifyProcess,完成签名校验、二次查询与订单推进
- SDK 配置 WxPay.Config:从全局配置读取 APPID/MCHID/KEY/证书路径等
- 二维码 qrcode.php:将 code_url 转为二维码图片供 PC 扫码
架构总览
微信支付插件通过统一入口 WxpayProvider 接收请求,交由 WxpayService 根据环境自动选择支付方式:
- 微信客户端(MicroMessenger)→ JSAPI 支付
- 移动端(IS_MOBILE)→ H5 支付(MWEB)
- 其他 → Native 扫码支付
所有支付方式共用同一异步通知地址,由 NotifyCallback 完成验签与二次确认,最终调用 PaymentService 推进订单状态。
sequenceDiagram
participant U as "用户"
participant P as "WxpayProvider"
participant S as "WxpayService"
participant WX as "微信支付API"
participant N as "NotifyCallback"
participant PS as "PaymentService"
U->>P : 发起支付(start)
P->>S : start(request)
alt 微信内
S->>WX : 统一下单(JSAPI)
WX-->>S : 预支付参数
S-->>U : 返回JSAPI参数(前端拉起支付)
else 移动端
S->>WX : 统一下单(H5/MWEB)
WX-->>S : mweb_url
S-->>U : 重定向至mweb_url
else PC
S->>WX : 统一下单(NATIVE)
WX-->>S : code_url
S-->>U : 展示二维码+轮询status
end
WX-->>N : 异步通知(notify)
N->>N : 验签+二次查询
N->>PS : markSucceeded(paymentSn, transactionId)
PS-->>N : 成功
N-->>WX : 返回success
详细组件分析
支付方式与流程
- JSAPI 支付(微信内)
- 通过 JsApiPay 获取 Openid,构造 WxPayUnifiedOrder 提交统一下单,返回 JSAPI 参数由前端拉起支付
- 成功后跳转订单页
- H5 支付(移动端浏览器)
- 使用 wechatAppPay 统一下单,trade_type=MWEB,返回 mweb_url,前端重定向完成支付
- 支付完成后回跳 finish 路由
- Native 扫码支付(PC)
- 统一下单 trade_type=NATIVE,获取 code_url,通过 qrcode.php 生成二维码
- 前端定时轮询 status 接口,查询交易状态并推进订单
flowchart TD
Start(["开始"]) --> UA{"UA判断"}
UA --> |MicroMessenger| JSAPI["JSAPI下单"]
UA --> |移动端| H5["H5(MWEB)下单"]
UA --> |其他| NATIVE["Native扫码下单"]
JSAPI --> JSAPIUI["前端拉起支付"]
H5 --> H5REDIR["重定向到mweb_url"]
NATIVE --> QR["生成二维码"]
JSAPIUI --> WaitNotify["等待异步通知"]
H5REDIR --> WaitNotify
QR --> Poll["轮询status"]
WaitNotify --> Verify["验签+二次查询"]
Poll --> Check{"是否SUCCESS?"}
Check --> |是| Mark["markSucceeded"]
Check --> |否| Continue["继续轮询"]
Verify --> Mark
Mark --> End(["结束"])
统一下单与参数生成
- 统一下单字段
- out_trade_no:使用 dou_order_payment.payment_sn
- total_fee:金额×100(分)
- notify_url:统一回调地址
- trade_type:JSAPI/NATIVE/MWEB
- body/attach/goods_tag/time_start/time_expire 等辅助信息
- 各方式差异
- JSAPI:需设置 Openid
- H5:需 spbill_create_ip,返回 mweb_url
- Native:返回 code_url,配合轮询
异步通知与结果处理
- 统一回调地址:route=plugin/wxpay/notify
- 处理流程
- 加载 SDK 并实例化 WxPayConfig
- 调用 Internal\NotifyCallback::Handle 完成验签
- 重写 Queryorder 进行二次查询确认
- 调用 PaymentService::markSucceeded 推进订单状态
- 发送站内邮件通知(如配置)
sequenceDiagram
participant WX as "微信支付"
participant SVC as "WxpayService"
participant CB as "NotifyCallback"
participant PS as "PaymentService"
WX->>SVC : POST /plugin/wxpay/notify
SVC->>CB : Handle(config, false)
CB->>CB : CheckSign()
CB->>CB : Queryorder(transaction_id)
CB->>PS : markSucceeded(paymentSn, transactionId, raw)
PS-->>CB : 成功
CB-->>WX : 返回success
订单查询与主动对账
- 主动对账接口 query:以 paymentSn 作为 out_trade_no 调用 orderQuery
- 状态映射
- SUCCESS:成功
- CLOSED/REVOKED/PAYERROR:关闭或失败
- NOTPAY/USERPAYING:待支付/支付中
- Native 轮询 status:按 paymentSn 查询并推进状态
退款申请(扩展说明)
- 当前插件未直接暴露退款入口,但 SDK 已支持退款相关 API(如 refund),可在现有 WxpayService 基础上扩展
- 退款需要配置证书路径(SSL_CERT_PATH/SSL_KEY_PATH),已在 buildConfig 中预留
小程序支付(接入说明)
- 小程序支付可通过 API 层调用 WxpayService 或独立服务发起统一下单(trade_type=JSAPI),并传入小程序 openid
- 本项目在 api/controller/user/WeixinController 中有小程序支付入口示例,可参考其调用方式
- 注意:小程序支付需确保 appid/appsecret/openid 正确配置
依赖关系分析
- WxpayProvider 依赖 WxpayService,对外暴露标准支付接口
- WxpayService 依赖:
- SDK:WxPay.Api(统一下单/查询)、WxPay.Config(配置)、WxPay.JsApiPay(JSAPI)、WxPay.NativePay(Native)、wechatAppPay(H5)
- Internal\NotifyCallback 继承 WxPayNotify,完成通知处理
- PaymentService 推进订单状态
- 配置文件 WxPay.Config 从 $GLOBALS['config_from_plugin'] 读取密钥与证书路径
classDiagram
class WxpayProvider {
+start(request) string
+notify(payload) string
+finish(payload) string
+status(payload) string
+query(request) PaymentQueryResult
}
class WxpayService {
+start(request) string
+notify(payload) string
+finish(payload) string
+status(payload) string
+query(request) PaymentQueryResult
-buildConfig() array
-bootSdk(files) void
}
class NotifyCallback {
+Queryorder(transactionId) bool
+NotifyProcess(objData, config, msg) bool
}
class WxPayConfig {
+GetAppId() string
+GetMerchantId() string
+GetKey() string
+GetSSLCertPath(&a,&b) void
}
WxpayProvider --> WxpayService : "委托"
WxpayService --> WxPayConfig : "读取配置"
WxpayService --> NotifyCallback : "通知处理"
性能与可靠性
- 轮询优化:Native 扫码在前端限制最大轮询次数与频率,避免无效请求
- 日志记录:每次统一下单、查询、通知均写入 storage/log/payment/wxpay 日志文件,便于追踪
- 幂等性:通知处理通过二次查询确认后再推进订单,降低重复通知风险
- 错误处理:查询失败或状态异常时返回明确状态码,便于上层重试或告警
故障排查指南
- 常见问题
- 签名错误:检查 KEY 是否正确,通知 URL 是否公网可达
- 统一下单失败:核对 appid/mchid/total_fee/spbill_create_ip 等必填字段
- H5 无法跳转:确认 mweb_url 与 redirect_url 拼接正确
- Native 无响应:检查 code_url 是否有效,轮询间隔与上限是否合理
- 定位方法
- 查看 storage/log/payment/wxpay/*.log 中的请求与响应
- 检查 WxpayService::buildConfig 生成的配置数组是否完整
- 使用微信商户平台订单号或交易号在后台查询订单状态
结论
DouPHP 微信支付插件通过统一的 Provider/Service 架构,结合微信官方 SDK,实现了 JSAPI、H5、Native 三种主流支付方式的无缝接入,并提供稳定的异步通知与主动对账能力。通过合理的配置与安全机制(签名验证、二次查询、日志记录),可有效保障支付流程的正确性与安全性。建议在现有基础上按需扩展退款与更多支付方式。
附录:配置项与接入方式速查
- 配置项
- appid:开发者ID(APPID)
- appsecret:开发者密码(仅 JSAPI 需要)
- mchid:商户号
- key:API 密钥(v2)
- SSL 证书路径:apiclient_cert.pem/apiclient_key.pem(退款等场景需要)
- 回调地址:/index.php?route=plugin/wxpay/notify
- 接入方式
- JSAPI:微信内支付,需 Openid
- H5:移动端浏览器支付,返回 mweb_url
- Native:PC 扫码支付,返回 code_url 并轮询
- 小程序:通过 API 层发起 JSAPI 支付(需小程序 openid)