PAYATHON 2026

WordPress RiPro主题配置支付宝当面付后无法生成二维码

支付小周

结论

页面一直转圈,通常不是“二维码生成失败”,而是创建当面付订单的 AJAX 请求没有返回主题所需的数据。建议重点检查三类问题:

  1. 支付接口模式与配置项不一致:只填写 appid、应用私钥和支付宝公钥,仅适用于主题调用支付宝开放平台 RSA2 接口的情况。如果当前通道使用的是旧版 PID/MD5 接口,PID 和 MD5 密钥留空会导致请求失败。
  2. 密钥填错或格式不符合要求:常见情况包括把“应用公钥”填入“支付宝公钥”,以及私钥类型、换行格式或 RSA/RSA2 签名方式不匹配。
  3. 后端报错,但前端没有显示错误信息: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 异常。

可以根据现象初步判断:

现象可能原因
500PHP 致命错误、支付 SDK 不兼容、缺少扩展
403WAF、安全插件、权限或 nonce 校验拦截
404AJAX 地址、固定链接或反向代理配置错误
返回 0WordPress AJAX action 未注册、权限校验失败或代码提前退出
返回整段 HTMLPHP 警告、登录页、缓存页或安全拦截页污染了 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 是否因跨域而丢失。

如果停用缓存或安全功能后支付恢复正常,应为支付路径配置精确的白名单,不要永久关闭整套安全机制。

推荐的排查顺序

按以下顺序处理,通常更容易找到问题:

  1. 在开发者工具中找到付款对应的 AJAX 请求,查看状态码和响应正文。
  2. 开启 WordPress 日志,复现一次问题并检查 PHP 错误。
  3. 确认主题调用的是 alipay.trade.precreate,而不是 PID/MD5 老接口。
  4. 确认 appid 属于已经签约当面付的开放平台应用。
  5. 重新核对应用私钥、应用公钥和支付宝公钥,特别注意不要把应用公钥填入“支付宝公钥”。
  6. 确认普通公钥模式与证书模式没有混用。
  7. 检查 RSA2、字符集和密钥格式。
  8. 查看支付宝返回的 sub_code、sub_msg,根据具体错误处理。
  9. 最后检查服务器网络、PHP 扩展、缓存、WAF 和主题兼容性。

如果 Network 响应和错误日志中都没有支付宝返回信息,应先解决主题后端异常。如果已经取得支付宝错误码,就不必继续猜测,直接根据该错误码检查应用、签名或权限配置。

备注:内容仅供参考。