如何设置异步通知地址
不同接口接收异步通知设置方式不同,可查看 哪些接口支持触发异步。
设置 notify_url 接收异步
对于支付产生的交易,支付宝会根据原始支付 API 中传入的异步通知地址 notify_url,通过 POST 请求的形式将支付结果作为参数通知到商家系统,接口调用 SDK 设置 notify_url 传参方式如下。
Alipay SDK(老版)
//Java版:
request.setNotifyUrl("商家自己的notify_url地址");
//PHP版:
$request->setNotifyUrl("商家自己的notify_url地址");
//.net版:
request.SetNotifyUrl("商家自己的notify_url地址");
//python版本:
request.notify_url="商家自己的notify_url地址"
//node.js版:
formData.addField('notifyUrl', '商家自己的notify_url地址');
Alipay Easy SDK(新版)
目前 Alipay Easy SDK 只支持 Java、PHP、.Net 语言,因此只有该 3 种语言有设置 notify_url 方式。
//Java版:
Factory.Payment.FaceToFace() // 调用asyncNotify扩展方法,可以为每次API调用,设置独立的异步商家自己的notify_url地址");
//PHP版:
Factory::payment()->FaceToFace() // 调用asyncNotify扩展方法,可以为每次API调用,设置独立的异步通知地址 // 此处设置的异步通知地址的优先级高于全局Config中配置的异步通知地址 ->asyncNotify("商家自己的notify_url地址");
//.net版:
Factory.Payment.FaceToFace() // 调用AsyncNotify扩展方法,可以为每此API调用,设置独立的异步通知地址 // 此处设置的异步通知地址的优先级高于全局Config中配置的异步通知地址 .AsyncNotify("商加自己的notify_url地址");
From 蚂蚁订阅接收异步
生活号、口碑、现金红包、单笔转账接口等异步通知发送到对应 APPID 应用的应用网关中,通过 POST 请求的形式将支付结果作为参数通知到商家系统。
如何接收可查看各产品文档上的异步说明。
异步通知返回参数介绍
支付宝查看支付宝开放平台文档中各接口的异步通知参数的详细说明。
以 App 支付为例,返回的异步通知参数如下(以下示例报文仅供参考,实际返回的详细报文请以实际返回为准)。
total_amount=2.00&buyer_id=20****7&body=大乐透2.1&trade_no=2016071921001003030200089909&refund_fee=0.00¬ify_time=2016-07-19 14:10:49&subject=大乐透2.1&sign_type=RSA2&charset=utf-8¬ify_type=trade_status_sync&out_trade_no=0719141034-6418&gmt_close=2016-07-19 14:10:46&gmt_payment=2016-07-19 14:10:47&trade_status=TRADE_SUCCESS&version=1.0&sign=kPbQIjX+xQc8F0/A6/AocELIjhhZnGbcBN6G4MM/HmfWL4ZiHM6fWl5NQhzXJusaklZ1LFuMo+lHQUELAYeugH8LYFvxnNajOvZhuxNFbN2LhF0l/KL8ANtj8oyPM4NN7Qft2kWJTDJUpQOzCzNnV9hDxh5AaT9FPqRS6ZKxnzM=&gmt_create=2016-07-19 14:10:44&app_id=20151*****3&seller_id=20881021****8¬ify_id=4a91b7a78a503640467525113fb7d8bg8e
异步通知验签
验签流程
为了帮助开发者调用开放接口,支付宝提供了 开放平台服务端 SDK 和 demo,包含 Java、PHP 和 .NET 等语言版本,封装了签名&验签、HTTP 接口请求等基础功能。为了避免验签出错强烈建议先下载对应语言版本的 SDK 并引入您的开发工程进行快速接入。
验签步骤
- 在通知返回参数列表中,除去 sign、sign_type 两个参数外,凡是通知返回回来的参数皆是待验签的参数。将剩下参数进行 url_decode,然后进行字典排序,组成字符串,得到待签名字符串;
生活号异步通知组成的待验签串里需要保留 sign_type 参数。 - 将签名参数(sign)使用 base64 解码为字节码串;
- 使用 RSA 的验签方法,通过签名字符串、签名参数(经过 base64 解码)及支付宝公钥验证签名。
- 验证签名正确后,必须再严格按照如下描述校验通知数据的正确性。
在上述验证通过后,商家必须根据支付宝不同类型的业务通知,正确的进行不同的业务处理,并且过滤重复的通知结果数据。
注意:
- 在支付宝的业务通知中,只有交易通知状态为 TRADE_SUCCESS 或 TRADE_FINISHED 时,支付宝才会认定为买家付款成功。
- 如果签约的产品支持退款,并且对应的产品默认支持能收到 TRADE_SUCCESS 或 TRADE_FINISHED 状态,该笔交易会先收到 TRADE_SUCCESS 交易状态,然后默认12个月该笔交易会再次收到 TRADE_FINISHED 状态。实际该笔交易只支付了一次,切勿认为该笔交易支付两次。
接口响应
收到异步通知后,商家输出 success 表示消息获取成功,支付宝就会停止发送异步,如果输出 fail,表示消息获取失败,支付宝会重新发送消息到异步地址。
建议在接收异步进行验签,如果验签成功输出 success,验签失败返回 fail,重新接收异步进行处理。
响应值 | 描述 | 是否重试 |
fail | 消息获取失败 | 重试 |
success | 消息获取成功 | 不重试 |
异步通知交易状态介绍
目前支付产品的交易状态大致分以下4种:
- WAIT_BUYER_PAY:交易创建,等待买家付款。
- TRADE_CLOSED:在指定时间段内未支付时关闭的交易或在交易完成全额退款成功时关闭的交易。
- TRADE_SUCCESS:商家签约的产品支持退款功能的前提下,买家付款成功。
- TRADE_FINISHED:商家签约的产品不支持退款功能的前提下,买家付款成功。或者,商家签约的产品支持退款功能的前提下,交易已经成功并且已经超过可退款期限。
无法接收异步通知如何处理
收不到回调原因
- 异步通知发送地址错误。notify_url、授权回调地址、应用网关地址弄混了。
- 异步地址无法公网访问。
- 异步地址设置方式错误。notify_url 传参,From 蚂蚁消息设置地址方式。
- 接口默认不触发相关的状态数据通知。
- 其实已经收到(其实是验签失败返回为空),但是没有做日志记录或者没有记录到通知。
核实异步地址是否正常
- 可通过目前提供的 云排查日志 查询对应交易的异步回调数据内容。
- 模拟 post 方式把云排查日志查询到的数据发送到接收异步回调页面,看异步页面能否正常接收到 post 发送过来的数据。
- 根据设置异步方式不同,可参考:
- 通过设置 notify_url 接收异步,详情可查看 收不到 notify_url 异步。
- 通过 From 蚂蚁订阅接收异步,详情可查看 收不到 From 蚂蚁消息。
为什么重复收到异步通知
重复收到异步通知主要是由于未返回 success 或异步通知不是同一个触发条件导致。
未返回 success
每当交易状态改变时,服务器异步通知页面就会收到支付宝发来的处理结果通知,程序执行完后必须打印输出 success,可通过 云排查 查询是否返回支付宝 success。
如果商家反馈给支付宝的字符不是 success 这 7 个字符,支付宝服务器会不断重发通知,直到超过 24 小时 22 分钟。一般情况下,25 小时以内完成 8 次通知(通知的间隔频率一般是:4m、10m、1h、2h、6h、15h)。
返回 success 示例代码
以下仅展示 Java、PHP、.NET 语言的示例,其它开发语言也是直接输出 success 即可。
JAVA
out.print("success");
PHP
echo "success";
.NET
Response.Write("success");
直接访问你的异步页面应该是输出(如下图)中的 success 这 7 个字符。
注意:浏览器上点击查看页面源代码,看到的是这个 7 个字符,有空格或者其它字符都会导致重复收到通知(建议大家做一下简单的验证)。
特别注意:返回的是纯文本内容,不要包含 html 等标签。
异步通知不是同一个触发条件
若在已经返回 success 后还会收到支付宝异步回调,请检查通知内容中的触发条件是否是相同的。
如支付产品在交易状态发生改变后,不同交易状态也可能会触发异步。
案例:若退款期限是 12 个月可退款,支付成功后,支付宝会发送 trade_success 的支付成功状态的异步通知,在 12 个月后支付宝会再次发送 trade_finished 的交易结束状态的异步通知,表示交易结束不允许退款。
注意:TRADE_SUCCESS 触发的异步停止后,可能受异步触发条件影响,TRADE_CLOSED 或者 TRADE_FINISHED 也会触发异步。
异步通知的特性
- 必须保证服务器异步通知页面(notify_url)上无任何字符,如空格、HTML 标签、开发系统自带抛出的异常提示信息等。
- 支付宝是用 POST 方式发送通知信息,因此该页面中获取参数的方式,如:request.Form(out_trade_no)、$_POST[out_trade_no]。
- 支付宝主动发起通知,该方式才会被启用。
- 只有在支付宝的交易管理中存在该笔交易,且发生了交易状态的改变,支付宝才会通过该方式发起服务器通知(即时到账交易状态为 等待买家付款 的状态默认是不会发送通知的)。
- 该方式的调试与运行必须在服务器上,即互联网上能访问。而且服务器间的交互不像页面跳转同步通知可以在页面上显示出来,这种交互方式是不可见的。
- 第一次交易状态改变(即时到账中此时交易状态是交易完成)时,不仅会返回同步处理结果,而且服务器异步通知页面也会收到支付宝发来的处理结果通知。
- 程序执行完后必须打印输出 success。如果商家反馈给支付宝的字符不是 success 这 7 个字符,支付宝服务器会不断重发通知,直到超过 24 小时 22 分钟。一般情况下,25 小时以内完成 8 次通知(通知的间隔频率一般是:4m,10m,10m,1h,2h,6h,15h) 。
- 程序执行完成后,该页面不能执行页面跳转。如果执行页面跳转,支付宝会收不到 success 字符,会被支付宝服务器判定为该页面程序运行出现异常,而重发处理结果通知。
- cookies、session 等在此页面会失效,即无法获取这些数据。
- 该方式的作用主要防止订单丢失,即页面跳转同步通知没有处理订单更新,它则去处理。
- 当商家收到服务器异步通知并打印出 success 时,服务器异步通知参数 notify_id 才会失效。也就是说在支付宝发送同一条异步通知时(包含商家并未成功打印出 success 导致支付宝重发数次通知),服务器异步通知参数 notify_id 是不变的。
- 异步通知 header 是 Content-Type:application/x-www-form-urlencoded; text/html; charset=utf-8 ,不是按照 RFC2183 RFC1521 标准来的。