- 金融科技
- 后端
【免费下载链接】pay
可能是我用过的最优雅的 Alipay/WeChat/Douyin/Unipay/江苏银行 的支付 SDK 扩展包了
本文是一份针对yansongda/pay支付宝OpenAPI V3交易关闭能力的实操指南,围绕Pay::alipay()->close()讲解调用方式、订单参数直传规则、notify_url的两级配置回落逻辑,以及底层插件管道(签名、验签、响应处理)的完整执行链路。读完本文,你将能够独立完成支付宝 V3 交易关闭的接入、参数排查与响应校验。
接口速览
支付宝 V3 交易关闭对应官方 OpenAPI 的alipay.trade.close(RESTful 路径/v3/alipay/trade/close)。在yansongda/pay中,入口方法定义如下:
| method | 说明 | 参数 | 返回值 |
|---|---|---|---|
close | 交易关闭 | array $order | Collection |
该方法在 src/Provider/Alipay.php 中定义,内部通过__call('close', [$order])分发到对应的 Shortcut 插件管道。
快速上手
关闭交易与发起支付一样简单,直接调用close()并传入订单参数即可:
use Yansongda\Pay\Pay; Pay::config($this->config); $result = Pay::alipay()->close([ 'out_trade_no' => '1514027114', // 'trade_no' => '2013112011001004330000121536', // 支付宝交易号,与 out_trade_no 二选一 ]);调用后返回Collection对象,可像数组一样读取字段,例如$result->get('trade_no')、$result->get('out_trade_no')。
提示:与 V2 的
__call默认分流不同,V3 接口需要显式传入 V3 Shortcut 插件数组(见 支付宝 V3 API 总览),但close()的调用形态与其余 V3 接口保持一致。
订单配置参数
交易关闭接口的业务参数采用snake_case 直传模式:所有参数与支付宝官方 V3 接口请求体无任何差别,直接以订单数组的形式传入即可,无需method、biz_content等外层包装。
常用参数包括:
| 参数 | 类型 | 说明 |
|---|---|---|
out_trade_no | string | 商户订单号,与trade_no二选一(两者都传时以trade_no为准) |
trade_no | string | 支付宝交易号,与out_trade_no二选一 |
operator_id | string | 商户操作员编号,用于风控与对账 |
notify_url | string | 该接口 Model 独有字段,见下文"两级配置"说明 |
完整的参数集合请对照官方 PHP SDK 的AlipayTradeCloseModel(字段如out_trade_no、trade_no、operator_id等均可直传),本仓库不做任何字段白名单过滤,传入什么就原样放入请求体。
notify_url 的两级配置规则
notify_url是官方AlipayTradeCloseModel独有的字段,在yansongda/pay中遵循两级配置回落:
- 订单参数优先:调用时显式传入
'notify_url' => 'https://...',则直接采用该值; - 租户配置回落:订单参数未提供时,回落读取租户配置中的
notify_url(对应AlipayConfig::getNotifyUrl(),见 src/Config/AlipayConfig.php); - 两者均未提供:不会向请求体注入该字段。
该逻辑在 src/Plugin/Alipay/V3/Pay/ClosePlugin.php 中实现:
$rocket->mergePayload([ '_method' => 'POST', '_url' => '/v3/alipay/trade/close', 'notify_url' => $payload?->get('notify_url', $config->getNotifyUrl()), ]);对应地,测试用例 tests/Shortcut/Alipay/V3/CloseShortcutTest.php 中显式传入notify_url后,断言其进入了最终请求 body,验证了"订单参数优先"的行为。
底层原理:插件管道执行链路
close()最终由 src/Shortcut/Alipay/V3/CloseShortcut.php 定义的插件管道完成整个请求生命周期:
return [ StartPlugin::class, // 管道启动,初始化 Rocket ClosePlugin::class, // 装载业务字段、_method、_url、notify_url AddPayloadBodyPlugin::class, // 将 payload 序列化为请求 body AddPayloadSignaturePlugin::class, // 生成 Authorization 签名头 AddRadarPlugin::class, // 组装 PSR-7 Request(URL、Headers、Body) // 管道 post 阶段逆序执行:先验签,后抛业务异常 ResponsePlugin::class, // 非 2xx 响应抛出业务异常 VerifySignaturePlugin::class,// 校验同步响应签名 ParserPlugin::class, // 解析响应为 Collection ];请求签名(AddPayloadSignaturePlugin)
AddPayloadSignaturePlugin 生成ALIPAY-SHA256withRSA格式的Authorization头,待签名组串由 5 行构成(authString、httpMethod、requestUri、requestBody、appAuthToken),并携带毫秒级时间戳与 UUID v4 nonce。若配置或订单参数中存在_app_auth_token(第三方应用授权),会额外注入alipay-app-auth-token请求头。
请求组装(AddRadarPlugin)
AddRadarPlugin 负责组装最终 PSR-7 请求:固定携带alipay-request-id(UUID v4,用于网关侧定位请求)、User-Agent: yansongda/pay-v3、JSON Content-Type,以及签名头Authorization。请求 URL 由 AlipayTrait::getAlipayV3Url 决定:沙箱模式走 V3 专用沙箱网关,正式模式走生产网关,均拼接业务路径/v3/alipay/trade/close。
响应验签(VerifySignaturePlugin)
VerifySignaturePlugin 对齐官方 SDK 的验签策略:
- HTTP 200 强制验签;非 200 响应仅在存在
alipay-signature时验签(防篡改),无签名直接放行进入错误处理; - 证书模式按
alipay-sn匹配本地支付宝公钥证书,缺失或不匹配直接抛InvalidSignException; - 校验
alipay-timestamp(13 位毫秒级,允许 ±300 秒偏差,与微信 V3 的秒级时间戳不同); - 组串
${timestamp}\n${nonce}\n${body}\n后验签,验签实现见 src/Traits/AlipayTrait.php。
业务异常处理(ResponsePlugin)
ResponsePlugin 在 post 阶段逆序执行时先于验签插件运行:当响应非 2xx 时,将错误体中的code/message并入异常消息,抛出InvalidResponseException,便于快速定位参数问题。
返回值说明
close()返回Collection,其中字段与支付宝官方 V3 接口响应体完全一致(无包裹层)。以交易关闭为例,典型返回字段包括:
out_trade_no:商户订单号trade_no:支付宝交易号
如需获取原始响应头(如alipay-timestamp、alipay-nonce等),可从 Rocket 的 destination origin 中读取;普通业务场景直接使用Collection即可。
测试验证
仓库为交易关闭提供了完整的单元测试与 HTTP 集成测试:tests/Shortcut/Alipay/V3/CloseShortcutTest.php:
testNormal断言插件管道顺序,并验证 post 阶段ResponsePlugin必须位于VerifySignaturePlugin之前(保证"有签才验、再抛异常"的顺序);testCloseHttp使用 Mockery 模拟 HTTP 客户端,构造带alipay-timestamp/alipay-nonce/alipay-signature/alipay-sn头的签名响应,验证notify_url进入请求 body、返回结果解析正确。
运行该文件对应的测试套件即可复现上述行为。
注意事项
- 参数二选一:
out_trade_no与trade_no必须提供其一,两者同时提供时支付宝以trade_no为准; - V3 仅证书模式:交易关闭走 V3 管道,租户必须配置
app_id、app_secret_cert、app_public_cert_path、alipay_public_cert_path四项(V2/V3 共用一套AlipayConfig,详见 src/Config/AlipayConfig.php); - 沙箱网关差异:V3 沙箱使用独立网关域名,与 V2 沙箱不同;
- 时间戳单位:V3 签名体系使用 13 位毫秒时间戳,若自行实现验签务必与微信 V3 的秒级时间戳区分;
- 交易状态约束:交易关闭仅对"未支付"状态的订单有效,已支付订单请使用退款(
refund)或撤销(cancel)能力,相关接口见 支付宝 V3 API 总览。
以上就是支付宝 V3 交易关闭的全部接入要点。参照本文代码即可完成对接,遇到返回状态码异常时,优先核对out_trade_no/trade_no的订单状态与参数取值。
- 金融科技
- 后端
【免费下载链接】pay
可能是我用过的最优雅的 Alipay/WeChat/Douyin/Unipay/江苏银行 的支付 SDK 扩展包了
相关推荐
pay 支付宝交易关闭(alipay.trade.close)实战指南:close 方法、参数与返回值全解析
pay 支付宝交易关闭(alipay.trade.close)实战指南:close 方法、参数与返回值全解析 本文以 pay 开源项目(Yansongda\Pa
金融科技后端支付宝 V3 交易退款:yansongda/pay 中 Refund 接口的完整接入指南与源码原理
支付宝 V3 交易退款:yansongda/pay 中 Refund 接口的完整接入指南与源码原理 本篇技术指南以 yansongda/pay 的支付宝 Ope
金融科技后端yansongda/pay 支付宝 V3 支付实战指南:付款码支付与扫码支付
yansongda/pay 支付宝 V3 支付实战指南:付款码支付与扫码支付 本指南聚焦 yansongda/pay 中支付宝 V3 网关的两大当面付场景——付
金融科技后端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考