H5支付返回url而非支付宝流水号,是文档有误吗?
明确结论
这是支付流程所处阶段不同造成的,并不一定是文档有误。
H5 支付接口主要用于生成支付跳转地址或 HTML 表单,以唤起支付宝收银台。此时用户还没有完成支付,商户通常只能确定自己的订单号 out_trade_no,无法提前取得支付宝交易号 trade_no。
trade_no 一般可以在以下环节获取:
- 支付完成后的异步通知
notify_url - 支付完成后的同步跳转
return_url - 使用
out_trade_no调用交易查询接口 - 某些接口在支付宝成功创建交易后会返回业务响应,但这和“生成 H5 支付页面”属于不同阶段
为什么接口返回的是 URL
H5 支付通常分为两个阶段:
- 商户系统生成支付请求。
- 用户打开支付 URL,进入支付宝收银台并完成支付。
生成 URL 时,商户提交的主要订单标识是:
out_trade_no
这个编号由商户系统生成,用于唯一标识本次订单。
支付宝侧的交易标识是:
trade_no
只有支付宝受理请求并创建对应交易后,trade_no 才会产生。如果用户尚未打开收银台,支付宝也还没有完成交易创建,商户自然无法预先取得这个值。
如果文档在“支付结果”“同步返回参数”或“异步通知参数”中列出了 trade_no,不代表生成支付 URL 时一定会返回该字段。还要确认这些字段对应的是哪个响应阶段。
推荐处理方式
1. 支付前保存商户订单号
生成支付请求前,先在自己的系统中创建订单,并保存 out_trade_no:
$outTradeNo = 'ORDER_' . date('YmdHis') . random_int(1000, 9999);
$order = [
'out_trade_no' => $outTradeNo,
'subject' => '商品订单',
'total_amount' => '99.00',
'product_code' => 'QUICK_WAP_WAY',
];
本地订单和支付 URL 应通过 out_trade_no 关联。初次创建订单时,不要依赖 trade_no。
2. 将支付页面返回给前端
不同 SDK 返回的内容可能是 URL、HTML 表单,也可能是可以直接输出的页面内容。例如:
$payResponse = $client->pageExecute($request, 'GET');
return [
'out_trade_no' => $outTradeNo,
'pay_url' => $payResponse,
];
这里的 $payResponse 仅作示意。实际返回类型取决于所用的支付宝 SDK、接口和调用方式,不能假定所有版本都会返回纯 URL。
3. 在异步通知中获取支付宝交易号
支付结果应主要以服务端异步通知为准。验签通过后,可以从通知数据中取得 trade_no:
$notifyData = $_POST;
if (!$alipayClient->rsaCheckV1($notifyData, $alipayPublicKey, 'RSA2')) {
http_response_code(400);
exit('failure');
}
$outTradeNo = $notifyData['out_trade_no'] ?? '';
$tradeNo = $notifyData['trade_no'] ?? '';
$tradeStatus = $notifyData['trade_status'] ?? '';
if (in_array($tradeStatus, ['TRADE_SUCCESS', 'TRADE_FINISHED'], true)) {
// 还需要核对订单号、金额、应用身份及收款方等信息。
// 更新订单时应保证幂等,避免重复通知造成重复处理。
}
exit('success');
这段代码只展示处理思路。具体的验签方法和参数形式,应以当前所用官方 SDK 的说明为准。
4. 必要时主动查询交易
如果异步通知还没有到达,可以使用商户订单号主动查询:
$request->setBizContent(json_encode([
'out_trade_no' => $outTradeNo,
], JSON_UNESCAPED_UNICODE));
$response = $client->execute($request);
查询接口通常支持使用 out_trade_no 或 trade_no 定位交易。具体 API 名称和响应结构,应以当前接入产品的官方文档为准。
能否在唤起支付宝之前获取 trade_no
通常不能。
在唤起收银台前,商户能够可靠掌握的是自己生成的 out_trade_no。如果业务要求提前取得支付宝侧的交易标识,需要确认当前产品是否提供独立的“预创建”或“交易创建”接口。即使存在,这类接口也可能不适用于 H5 支付,不能直接代替 H5 收银台接口。
建议使用下面的关联关系:
本地订单 ID
└── out_trade_no
└── 支付成功或查询后得到 trade_no
注意事项
- 不要只根据浏览器是否跳转到
return_url判断支付成功。用户可能关闭页面,跳转参数也可能被伪造。 - 收到异步通知后,必须先验签,再核对
out_trade_no、支付金额、应用身份和收款方信息。 - 通知可能重复发送,因此订单更新和发货逻辑必须具备幂等性。
- 不要把支付 URL 中的某个参数误认为
trade_no。 - 如果文档确实把
trade_no标为“生成支付 URL 接口的即时响应字段”,还需核对接口名称、SDK 版本和文档章节。该字段也可能描述的是回调参数或查询结果。
备注:内容仅供参考。
