新版 EasySDK 如何支持网页版网银支付及 GET 支付链接
结论
EasySDK 的 page.pay 和 wap.pay 主要用于生成支付宝收银台表单。服务端通常会把返回的 HTML 表单输出到浏览器,由浏览器自动提交,因此不适合用来在服务端生成 GET 支付链接,再交给前端跳转。
如需 GET 支付链接,可以使用支付宝通用 SDK,创建 AlipayTradePagePayRequest,并在调用 pageExecute 时指定 GET。手机网站支付则使用 AlipayTradeWapPayRequest。
用户能否在充值页面预先选择银行,并不由 SDK 决定。SDK 只负责请求签名和调用支付接口,支付宝收银台支持哪些银行、是否允许指定银行,取决于商户签约的支付产品及当前接口文档。新版 alipay.trade.page.pay 通常会跳转到支付宝收银台,由用户选择可用的支付方式,不能直接套用旧版接口中的银行代码参数。
推荐的支付流程
可以按以下流程处理:
- 前端展示充值金额、银行卡等选项。
- 前端向服务端提交充值请求。
- 服务端创建本地充值订单,并生成唯一的
out_trade_no。 - 服务端通过通用 SDK 生成支付宝 GET 支付链接。
- 服务端把链接返回给前端。
- 前端通过
window.location.href跳转到支付宝收银台。 - 支付结果以支付宝异步通知为准,不能只看同步跳转结果。
如果前端选择的“银行卡类型”仅用于业务记录,可以将其保存到本地订单中。在支付宝没有明确支持相关参数的情况下,不要自行拼接 bank_code、defaultbank 等字段。
PHP 通用 SDK 示例
下面使用通用版支付宝 PHP SDK。示例中的类名和基本调用方式适用于常见版本,实际命名空间和证书配置仍应以项目安装的 SDK 版本为准。
<?php
$aop = new AopClient();
$aop->gatewayUrl = 'https://openapi.alipay.com/gateway.do';
$aop->appId = 'your_app_id';
$aop->rsaPrivateKey = 'your_merchant_private_key';
$aop->alipayrsaPublicKey = 'your_alipay_public_key';
$aop->signType = 'RSA2';
$aop->format = 'json';
$aop->charset = 'UTF-8';
$request = new AlipayTradePagePayRequest();
$request->setNotifyUrl('https://example.com/alipay/notify');
$request->setReturnUrl('https://example.com/alipay/return');
$request->setBizContent(json_encode([
'out_trade_no' => 'RECHARGE_202609090001',
'total_amount' => '100.00',
'subject' => '账户充值',
'product_code' => 'FAST_INSTANT_TRADE_PAY',
], JSON_UNESCAPED_UNICODE));
// 指定 GET,返回已经完成签名的支付链接
$payUrl = $aop->pageExecute($request, 'GET');
// 以 JSON 形式返回给前端
header('Content-Type: application/json; charset=utf-8');
echo json_encode([
'pay_url' => $payUrl,
], JSON_UNESCAPED_UNICODE);
前端收到链接后跳转:
const response = await fetch('/api/recharge', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
amount: '100.00',
bankType: 'ICBC'
})
});
const result = await response.json();
if (result.pay_url) {
window.location.href = result.pay_url;
}
手机网站支付的写法相近:
$request = new AlipayTradeWapPayRequest();
$request->setNotifyUrl('https://example.com/alipay/notify');
$request->setReturnUrl('https://example.com/alipay/return');
$request->setBizContent(json_encode([
'out_trade_no' => 'RECHARGE_202609090002',
'total_amount' => '100.00',
'subject' => '账户充值',
'product_code' => 'QUICK_WAP_WAY',
'quit_url' => 'https://example.com/recharge',
], JSON_UNESCAPED_UNICODE));
$payUrl = $aop->pageExecute($request, 'GET');
如果当前 PHP SDK 的 pageExecute() 不接受第二个参数,需要检查项目实际安装版本的方法签名,不能假定所有版本的调用方式完全一致。
EasySDK 应该怎么处理
如果项目已经在使用 EasySDK,可以继续通过它完成普通的支付创建、查询、退款和通知验签。但在必须返回 GET URL 的场景中,直接使用通用 SDK 会更清楚。
如果 EasySDK 的高级封装只提供 POST 表单,不建议直接修改 vendor 目录中的源码,原因包括:
- Composer 更新后,本地修改可能被覆盖。
- 团队难以区分官方代码和本地补丁。
- 后续切换 SDK 版本时容易遇到兼容问题。
- 手工拼接支付链接可能遗漏签名、编码或公共参数。
如果必须保留 EasySDK,可以让它与通用 SDK 并存。两者使用同一个 app_id、商户私钥和支付宝公钥,GET 支付链接则单独通过通用 SDK 生成。
关于预先指定银行卡
这里要区分两个概念:
- “页面上让用户选择银行卡”属于商户自己的交互,可用于展示、统计或后续业务判断。
- “让支付宝收银台直接进入某家银行”属于支付宝支付产品提供的能力,无法由 SDK 的封装方式决定。
旧接口中曾有直接指定网银或默认银行的参数,但不能在未经确认的情况下将这些参数用于 alipay.trade.page.pay。即使参数可以正常签名并发送,支付宝网关仍可能忽略或拒绝它。
建议先确认以下内容:
- 商户账号签约的是电脑网站支付、手机网站支付,还是单独的网银支付产品。
- 当前签约产品是否支持直接指定银行。
- 对应接口是否明确提供了银行代码字段及其可用值。
- 这项能力是否需要单独申请或开通。
如果当前产品只支持标准电脑网站支付,就应跳转到支付宝收银台,由收银台展示该用户可用的付款方式。
异步通知必须作为支付依据
前端跳转回来只能说明用户返回了商户页面,并不表示付款已经成功。订单入账必须以异步通知验签和订单查询结果为准。
处理通知时至少需要核对:
- 通知签名是否合法。
app_id是否属于当前应用。out_trade_no是否存在。total_amount是否与本地订单金额一致。seller_id是否符合预期。trade_status是否属于可入账状态。- 同一订单是否已经处理,以免重复充值。
异步通知处理必须具备幂等性。业务处理完成后,再按照支付宝接口要求返回成功响应。
关于 GitHub 项目是否仍在维护
某个 2021 年提交的 PR 长期没有合并,并不足以证明项目已经停止维护。PR 未被采纳也可能与接口设计、兼容性、产品策略或维护优先级有关。
判断项目目前是否仍由官方持续维护,需要查看仓库最近的 release、commit、issue 回复情况,以及支付宝开放平台公布的 SDK 下载入口。如果业务需要 GET 跳转,无需等待 EasySDK 合并相关改动,可以直接使用通用 SDK 的 pageExecute($request, 'GET')。
备注:内容仅供参考。
