WordPress RiPro主题配置支付宝当面付后无法生成二维码
结论
页面一直转圈,通常不是“二维码生成失败”,而是创建当面付订单的 AJAX 请求没有返回主题所需的数据。建议重点检查三类问题:
- 支付接口模式与配置项不一致:只填写
appid、应用私钥和支付宝公钥,仅适用于主题调用支付宝开放平台 RSA2 接口的情况。如果当前通道使用的是旧版 PID/MD5 接口,PID 和 MD5 密钥留空会导致请求失败。 - 密钥填错或格式不符合要求:常见情况包括把“应用公钥”填入“支付宝公钥”,以及私钥类型、换行格式或 RSA/RSA2 签名方式不匹配。
- 后端报错,但前端没有显示错误信息:PHP 异常、支付宝 API 报错、服务器无法连接支付宝网关,都可能让页面持续显示加载状态。
开通当面付、手机网站支付和电脑网站支付,只能说明账号取得了相关产品权限,不能证明网站中的应用、密钥和接口调用配置正确。
先确认主题使用的是哪套接口
不同版本或经过二次修改的 RiPro,支付模块的实现可能不同,不能只看后台有哪些输入框来判断接口类型。
检查支付宝支付通道的说明、源码或实际网络请求,确认当前调用的是哪一种模式:
- 开放平台接口,通常使用
app_id、应用私钥和支付宝公钥,签名方式为RSA2。 - 老版即时到账或 MD5 接口,通常需要合作伙伴身份
PID和 MD5 密钥。
如果代码调用 alipay.trade.precreate,一般使用的是当面付 RSA/RSA2 模式,PID 和 MD5 密钥通常可以留空。如果代码仍在读取 partner、seller_id、key,或者采用 MD5 签名,就不能只填写 appid 和 RSA 密钥。
不要为了填满配置项而随意填写 PID 或 MD5 密钥。先确认主题实际使用的接口协议。
检查开放平台应用与产品权限
登录支付宝开放平台,核对当前配置对应的应用:
- 后台填写的
appid必须属于配置密钥时所选择的应用。 - 当面付能力必须签约并绑定到该应用,只有支付宝商户账户开通了这项能力还不够。
- 应用需要处于允许正式调用的状态。
- 网站调用正式网关时,应使用正式应用的密钥,不能混入沙箱应用配置。
- 接口调用账号、签约商户和应用之间的关系必须正确。
正式环境网关通常为:
https://openapi.alipay.com/gateway.do
沙箱环境使用另一套网关和应用信息。如果混用正式 appid、沙箱私钥和正式支付宝公钥,签名一定无法通过。
正确区分三种密钥
支付宝开放平台的 RSA2 配置中,通常会出现三种容易混淆的内容:
- 应用私钥:保存在网站服务器中,用于为请求签名。
- 应用公钥:上传到支付宝开放平台,供支付宝验证网站的签名。
- 支付宝公钥:从开放平台应用配置页获取,网站用它验证支付宝返回的数据。
RiPro 后台的“支付宝公钥”必须填写支付宝提供的公钥,不能填写自己生成的应用公钥。
还要确认主题采用哪种密钥接入方式:
- 普通公钥模式;
- 应用公钥证书模式。
如果应用采用证书模式,而主题后台只有“应用私钥”和“支付宝公钥”两个文本框,主题可能不支持证书模式。此时需要改用主题支持的普通公钥方式,或者升级、修改支付模块,使其能够加载应用证书、支付宝公钥证书和支付宝根证书。
核对 RSA2 和密钥长度
如果主题设置中可以选择签名方式,先确认以下配置:
sign_type=RSA2
charset=utf-8
RSA2 使用 SHA-256 签名。应用私钥必须与上传到当前支付宝应用的应用公钥配对。
部分旧版支付模块只支持 RSA,或者在代码中固定使用 RSA。如果开放平台配置使用 RSA2,而主题使用 RSA,也会出现签名或验签错误。除了检查后台选项,还要查看最终请求中的 sign_type。
检查密钥格式
有些主题后台要求填写“不带头尾、保持单行”的裸密钥,有些则要求完整的 PEM 内容,具体取决于代码加载密钥的方式。
完整 PEM 私钥示例:
-----BEGIN PRIVATE KEY-----
MIIE...
-----END PRIVATE KEY-----
另一种常见格式是:
-----BEGIN RSA PRIVATE KEY-----
MIIE...
-----END RSA PRIVATE KEY-----
支付宝开放平台工具生成的私钥类型,必须与主题内部 openssl_pkey_get_private() 的处理方式兼容。如果后台说明要求裸密钥,不要自行添加 PEM 头尾。如果代码直接通过 OpenSSL 读取完整私钥,则要保留正确的头尾和换行。
PHP 中常见的裸密钥转换方式如下,这段代码只用于说明格式处理逻辑:
function formatPrivateKey(string $key): string
{
$key = str_replace(
["\r", "\n", '-----BEGIN PRIVATE KEY-----', '-----END PRIVATE KEY-----'],
'',
trim($key)
);
return "-----BEGIN PRIVATE KEY-----\n"
. chunk_split($key, 64, "\n")
. "-----END PRIVATE KEY-----";
}
如果原始私钥属于 RSA PRIVATE KEY 类型,不能未经判断就改成 PRIVATE KEY。两者对应的编码格式可能不同,应根据实际生成方式处理。
还要注意以下几点:
- 密钥前后不能有空格、中文引号或不可见字符。
- 不要把
\n这两个字符误当成真正的换行。 - 从网页复制密钥时,注意不要漏掉首尾字符。
- 不要把真实私钥放入前端 JavaScript、公开日志或工单截图。
从浏览器定位一直转圈的直接原因
打开浏览器开发者工具,切换到 Network,重新点击付款,然后找到对应的 AJAX 请求。WordPress 主题的常见请求地址可能包含:
/wp-admin/admin-ajax.php
查看以下信息:
- HTTP 状态码;
- Response 正文;
- 请求是否长时间停留在
Pending; - 返回内容是 JSON、HTML、空内容还是 PHP 错误;
- Console 中是否有 JavaScript 异常。
可以根据现象初步判断:
| 现象 | 可能原因 |
|---|---|
500 | PHP 致命错误、支付 SDK 不兼容、缺少扩展 |
403 | WAF、安全插件、权限或 nonce 校验拦截 |
404 | AJAX 地址、固定链接或反向代理配置错误 |
返回 0 | WordPress AJAX action 未注册、权限校验失败或代码提前退出 |
| 返回整段 HTML | PHP 警告、登录页、缓存页或安全拦截页污染了 JSON |
一直 Pending | 外部请求超时、DNS/TLS 问题或 PHP 进程阻塞 |
| JSON 中有支付宝错误码 | 应按 sub_code 和 sub_msg 排查接口配置 |
前端持续转圈,往往是因为支付脚本没有处理失败分支。即使页面没有显示错误,Network 中的响应通常也能提供有用线索。
查看 WordPress 和 PHP 错误日志
可以临时开启 WordPress 调试日志:
define('WP_DEBUG', true);
define('WP_DEBUG_LOG', true);
define('WP_DEBUG_DISPLAY', false);
这些配置应写入 wp-config.php,并放在以下注释之前:
/* That's all, stop editing! Happy publishing. */
再次发起付款后,检查:
wp-content/debug.log
同时查看 PHP-FPM、Web 服务器和主机控制面板中的错误日志,重点搜索:
Fatal error
Uncaught
openssl
curl
alipay
sign
json
admin-ajax.php
排查结束后,应在生产环境中关闭调试,或者至少确保错误信息不会直接显示给访客:
define('WP_DEBUG', false);
不要把应用私钥、完整请求参数或用户付款信息写入公开日志。
记录支付宝 API 的真实返回值
如果支付模块忽略了错误,可以在服务端临时记录脱敏后的响应。调用 alipay.trade.precreate 后,至少要检查:
$response = $result->alipay_trade_precreate_response ?? null;
if (!$response) {
error_log('Alipay response object is missing');
return;
}
if (($response->code ?? '') !== '10000') {
error_log(sprintf(
'Alipay error: code=%s, sub_code=%s, msg=%s, sub_msg=%s',
$response->code ?? '',
$response->sub_code ?? '',
$response->msg ?? '',
$response->sub_msg ?? ''
));
}
成功响应通常会包含 qr_code。前端只有拿到这个字段,才能生成或显示二维码:
if (($response->code ?? '') === '10000' && !empty($response->qr_code)) {
wp_send_json_success([
'qr_code' => $response->qr_code,
]);
}
wp_send_json_error([
'message' => $response->sub_msg ?? $response->msg ?? '支付宝下单失败',
'sub_code' => $response->sub_code ?? '',
]);
实际对象结构由主题使用的支付宝 SDK 决定,变量名不能直接照搬。需要确认的不只是请求有没有完成,还要保留支付宝返回的 code、sub_code、msg 和 sub_msg。
常见的排查方向有:
isv.invalid-signature:签名、私钥或参数编码有误;isv.invalid-app-id:appid错误或混用了不同环境;- 权限类错误:应用没有对应的产品权限;
- 商户状态类错误:签约、账号或收款能力异常;
- 参数类错误:订单号、金额、标题或通知地址不符合接口要求。
具体含义应以当次接口响应和支付宝开放平台对应接口的文档为准。
检查服务器运行环境
当面付订单由服务器连接支付宝网关创建。浏览器能够打开支付宝,不代表服务器也能正常访问网关。
至少要确认:
- PHP 已启用
curl和openssl。 - 服务器能够通过 HTTPS 访问支付宝开放平台网关。
- 系统时间和时区没有明显错误。
- CA 根证书有效,没有 TLS 证书验证错误。
- 主机防火墙、云安全策略和代理没有拦截外部 HTTPS 请求。
- PHP 的
max_execution_time和网络超时设置合理。 - 当前 PHP 版本与主题内置的支付宝 SDK 兼容。
如果日志中出现:
Call to undefined function curl_init()
说明服务器缺少 cURL 扩展。
如果出现:
SSL certificate problem
应更新服务器的 CA 证书,或者修复 PHP cURL 的证书配置。不建议长期关闭 SSL 验证来绕过问题。
排除缓存和安全插件干扰
支付请求和订单接口不应经过页面缓存、CDN 缓存或静态化处理。可以暂时排除:
/wp-admin/admin-ajax.php
还要排除主题实际使用的支付回调和订单查询路径。
同时检查:
- 安全插件是否拦截 AJAX 请求;
- CDN 或 WAF 是否将请求判定为异常;
- JavaScript 合并或延迟加载是否破坏支付脚本;
- REST API 或
admin-ajax.php是否被禁止访问; - 用户登录状态、nonce 或 Cookie 是否因跨域而丢失。
如果停用缓存或安全功能后支付恢复正常,应为支付路径配置精确的白名单,不要永久关闭整套安全机制。
推荐的排查顺序
按以下顺序处理,通常更容易找到问题:
- 在开发者工具中找到付款对应的 AJAX 请求,查看状态码和响应正文。
- 开启 WordPress 日志,复现一次问题并检查 PHP 错误。
- 确认主题调用的是
alipay.trade.precreate,而不是 PID/MD5 老接口。 - 确认
appid属于已经签约当面付的开放平台应用。 - 重新核对应用私钥、应用公钥和支付宝公钥,特别注意不要把应用公钥填入“支付宝公钥”。
- 确认普通公钥模式与证书模式没有混用。
- 检查
RSA2、字符集和密钥格式。 - 查看支付宝返回的
sub_code、sub_msg,根据具体错误处理。 - 最后检查服务器网络、PHP 扩展、缓存、WAF 和主题兼容性。
如果 Network 响应和错误日志中都没有支付宝返回信息,应先解决主题后端异常。如果已经取得支付宝错误码,就不必继续猜测,直接根据该错误码检查应用、签名或权限配置。
备注:内容仅供参考。
