关于支付宝异步通知的那些事

来自    签名与验签 | 
作者:我是个导演  |  更新于:2017-07-14 11:12:49     
一、如何指定接收异步通知的地址

    对于支付产生的交易,支付宝会根据原始支付API中传入的异步通知地址notify_url,通过POST请求的形式将支付结果 作为参数通知到商户系统。
    以app支付为例,支付请求中notify_url参数的(如下图):

    

二、异步通知返回参数介绍

    支付宝通过POST请求的形式将支付结果作为参数通知到商户系统。各接口返回的异步通知参数可能会略有不同,具体请参见支付宝开放平台文档中各接口的异步通知参数的详细说明。
以app支付为例,返回的异步通知参数如下(以下示例报文仅供参考,实际返回的详细报文请以实际返回为准):
    
https://api.xx.com/receive_notify.htm?total_amount=2.00&buyer_id=2088102116773037&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=2015102700040153&seller_id=2088102119685838¬ify_id=4a91b7a78a503640467525113fb7d8bg8e

三、异步通知的验签
    为了帮助开发者调用开放接口,我们提供了开放平台服务端sdk和demo,包含JAVA、PHP和.NET三语言版本,封装了签名&验签、HTTP接口请求等基础功能。为了避免验签出错强烈建议先下载对应语言版本的SDK并引入您的开发工程进行快速接入。

  
其验签步骤为:
    第一步: 在通知返回参数列表中,除去sign、sign_type两个参数外,凡是通知返回回来的参数皆是待验签的参数。
    第二步: 将剩下参数进行url_decode, 然后进行字典排序,组成字符串,得到待签名字符串:
    第三步: 将签名参数(sign)使用base64解码为字节码串。
    第四步: 使用RSA的验签方法,通过签名字符串、签名参数(经过base64解码)及支付宝公钥验证签名。
    第五步:在步骤四验证签名正确后,必须再严格按照如下描述校验通知数据的正确性。

    1、商户需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号;
    2、判断total_amount是否确实为该订单的实际金额(即商户订单创建时的金额);
    3、校验通知中的seller_id(或者seller_email) 是否为out_trade_no这笔单据的对应的操作方(有的时候,一个商户可能有多个seller_id/seller_email);
    4、验证app_id是否为该商户本身。

    上述1、2、3、4有任何一个验证不通过,则表明本次通知是异常通知,务必忽略。在上述验证通过后商户必须根据支付宝不同类型的业务通知,正确的进行不同的业务处理,并且过滤重复的通知结果数据。在支付宝的业务通知中,只有交易通知状态为TRADE_SUCCESS或TRADE_FINISHED时,支付宝才会认定为买家付款成功。

四、无法接收到异步通知怎么办

    自查方案一:【点击查看
    自查方案二:【点击查看

五、异步通知中的交易状态介绍
   请参考这个详情帖子:https://openclub.alipay.com/read.php?tid=1295&fid=25

六、为什么会重复不断的收到支付宝的异步通知

每当交易状态改变时,服务器异步通知页面就会收到支付宝发来的处理结果通知,程序执行完后必须打印输出success。如果商户反馈给支付宝的字符不是success这7个字符,支付宝服务器会不断重发通知,直到超过24小时22分钟。一般情况下,25小时以内完成8次通知(通知的间隔频率一般是:4m,10m,10m,1h,2h,6h,15h)。
其中,若退款期限是3个月可退款,支付成功后,支付宝会发送trade_success的支付成功状态的异步通知,在3个月后支付宝会再次发送trade_finished的交易结束状态的异步通知,表示交易结束不允许退款。

  返回success代码示例:
   JAVA:
out.println("success");

   PHP:
echo "success";

   .NET:
Response.Write("success");
 其他开发语言也是直接输出success即可

    直接访问你的异步页面应该是输出(如下图)中的success这7个字符
注意:浏览器上点击查看页面源代码,看到的是这个7个字符,有空格或者其他字符都会导致重复收到通知(建议大家做一下简单的验证)
   


   特别注意:返回的是纯文本内容,不要包含html等标签

七、异步通知的特性
   1.必须保证服务器异步通知页面(notify_url)上无任何字符,如空格、HTML标签、开发系统自带抛出的异常提示信息等
   2.支付宝是用POST方式发送通知信息,因此该页面中获取参数的方式,如:request.Form(“out_trade_no”)、$_POST[‘out_trade_no’];
   3.支付宝主动发起通知,该方式才会被启用;
   4.只有在支付宝的交易管理中存在该笔交易,且发生了交易状态的改变,支付宝才会通过该方式发起服务器通知(即时到账交易状态为“等待买家付款”的状态默认是不会发送通知的);
   5.服务器间的交互,不像页面跳转同步通知可以在页面上显示出来,这种交互方式是不可见的;
   6.第一次交易状态改变(即时到账中此时交易状态是交易完成)时,不仅会返回同步处理结果,而且服务器异步通知页面也会收到支付宝发来的处理结果通知;
   7.程序执行完后必须打印输出success。如果商户反馈给支付宝的字符不是success这7个字符,支付宝服务器会不断重发通知,直到超过24小时22分钟。一般情况下,25小时以内完成8次通知(通知的间隔频率一般是:4m,10m,10m,1h,2h,6h,15h)
    8.程序执行完成后,该页面不能执行页面跳转。如果执行页面跳转,支付宝会收不到success字符,会被支付宝服务器判定为该页面程序运行出现异常,而重发处理结果通知;
    9.cookies、session等在此页面会失效,即无法获取这些数据;
    10.该方式的调试与运行必须在服务器上,即互联网上能访问;
    11.该方式的作用主要防止订单丢失,即页面跳转同步通知没有处理订单更新,它则去处理;
    12.当商户收到服务器异步通知并打印出success时,服务器异步通知参数notify_id才会失效。也就是说在支付宝发送同一条异步通知时(包含商户并未成功打印出success导致支付宝重发数次通知),服务器异步通知参数notify_id是不变的。
我是个导演 | 2017-09-21 11:38:53
任务兔:怎么判断是支付通知还是退款通知 ?回到原帖
退款状态包含:
1、REFUND_SUCCESS:退款成功,分两种情况
全额退款情况:trade_status= TRADE_CLOSED,而refund_status=REFUND_SUCCESS
非全额退款情况:trade_status= TRADE_SUCCESS,而refund_status=REFUND_SUCCESS
2、REFUND_CLOSED:退款关闭
残念漫者 | 2017-09-08 09:47:08
确定第一次异步通知是在4m之后吗?而不是付款完成后立即?
我是个导演 | 2017-09-08 09:50:14
残念漫者:确定第一次异步通知是在4m之后吗?而不是付款完成后立即?回到原帖
一共8次,第一个支付完成以后就会通知,后面是剩下的7次通知时间
残念漫者 | 2017-09-08 10:04:18
我是个导演:一共8次,第一个支付完成以后就会通知,后面是剩下的7次通知时间回到原帖
但是沙箱测试的时候没有立即收到过
我是个导演 | 2017-09-08 10:09:05
残念漫者:但是沙箱测试的时候没有立即收到过回到原帖
如果没有立即收到,可以提供appid+订单号+交易号。这边查一下
我是个导演 | 2017-09-08 10:29:24
残念漫者:但是沙箱测试的时候没有立即收到过回到原帖
提供一个今天交易的交易号
残念漫者 | 2017-09-08 10:34:02
我是个导演:提供一个今天交易的交易号回到原帖
今天显示服务繁忙...好了,再询问你吧
我是个导演 | 2017-09-08 10:42:31
残念漫者:今天显示服务繁忙...好了,再询问你吧回到原帖
好的
杭州大嫁网 | 2017-09-09 17:48:19
为什么我付款成功了,也进入到异步请求的页面的,可是传过来的$_POST为空是怎么回事
我是个导演 | 2017-09-11 09:56:39
杭州大嫁网:为什么我付款成功了,也进入到异步请求的页面的,可是传过来的$_POST为空是怎么回事回到原帖
php要把post 记录在日志中,确认一下你是否日志已经开启,也可以提供你的:测试环境+交易号+订单号 测试时间 最好是当天 我这边查一下
千帆 | 2017-09-13 14:34:57
导演你好,今天测试,正式环境中支付成功,有同步返回,但是没有异步通知。好像支付宝服务器没有POST过我们服务器。这个你可以查么?
我是个导演 | 2017-09-13 14:57:28
千帆:导演你好,今天测试,正式环境中支付成功,有同步返回,但是没有异步通知。好像支付宝服务器没有POST过我们服务器。这个你可以查么?回到原帖
建议你这边根据这个帖子自查:https://openclub.alipay.com/read.php?tid=1677&fid=25&page=1 然后按照上面帖子提供相关信息,我这边也可以查一下
千帆 | 2017-09-13 16:30:12
我是个导演:建议你这边根据这个帖子自查:https://openclub.alipay.com/read.php?tid=1677&fid=25&page=1 然后按照上面帖子提供相关信息,我这边也可以查一下回到原帖
十分感谢导演的帮助!!原来是我这边服务器路由设置问题,在接受通知接口开放GET,没有开放POST。
码农松 | 2017-09-17 00:06:57
我从异步通知获取到的参数集合paramMap,里面的value都是数组形式的。。然后在调用sdk进行验签的时候String sign = paramMap.get("sign").就报错。[Ljava.lang.String; cannot be cast to java.lang.String。。。这个是什么原因造成的呢?参数我直接获取,也没动过,,然后直接调用的sdk进行验签。。谁给解答下。
我的回复
回复数
  145
阅读数
  27040

返回顶部