支付宝异步通知notify_url与return_url

Posted wangjiuwang

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了支付宝异步通知notify_url与return_url相关的知识,希望对你有一定的参考价值。

支付宝接口使用文档说明 支付宝异步通知(notify_url)与return_url. 

现支付宝的通知有两类。 
A服务器通知,对应的参数为notify_url,支付宝通知使用POST方式 
B页面跳转通知,对应的参数为return_url,支付宝通知使用GET方式 (通知地址不需要像以前一样去账户内设置,而是由客户在支付的时候通过参数传递给我地址。 

例如 notify_url=http://www.xxx.com/notify_alipay.jsp 注意:www.XXX.com是您网站的域名,也可以用ip地址代替。对于服务器通知,ip地址一定是公网的,私有地址(例如10.2.1.1或者 192.168.1.1)支付宝无法通知到客户端) 

以下内容来自支付宝官方网站,不过由于地址改变了,导致原帖无法访问,通过快照查找到其内容,特分享一下. 

1. 确认您使用的接口是用notify_url还是return_url。 
2. notify_url为服务器通知,支付宝可以保证99.9999%的通知到达率,前提是您的网络通畅。 
3. return_url为网页重定向通知,是由客户的浏览器触发的一个通知,若客户去网银支付,也会受银行接口影响,由于各种影响因素特别多,所以该种类型的通知支付宝不保证其到达率。 
买家付款成功后,会跳到 return_url所在的页面,这个页面可以展示给客户看,这个页面只有付款成功才会跳转,并且只跳转一次.. 
notify_url: 服务器后台通知,这个页面是支付宝服务器端自动调用这个页面的链接地址,这个页面根据支付宝反馈过来的信息修改网站的定单状态,更新完成后需要返回一个success给支付宝.,不能含有任何其它的字符包括html语言. 
流程:买家付完款(trade_status=WAIT_SELLER_SEND_GOODS)--->支付宝通知 notify_url--->如果反馈给支付宝的是success(表示成功,这个状态下不再反馈,如果不是继续通知,一般第一次发送和第二次发送的时间间隔是3分钟) 
剩下的过程,卖家发货,买家确认收货,交易成功都是这个流程 

------------------------------------------------------------------- 
大家想必都有这种困惑——拿到支付宝的接口代码后,尽管里面的程序有注释,接口代码包中也附有开发说明,但还是不知道该如何入手。这不难想象是什么原因,因为自己并不了解这个接口的工作原理是什么? 
那么这篇文章就是要向大家全面展示关于支付宝接口的所有东西,以便大家能快速上手把接口接入自己的项目中,也能帮助那些已经对支付宝接口有所了解的程序开发者们更了解支付宝的一些通用规则、特殊用途等。 

正题开始—— 

一、 结构 
a) 一般由两部分组成,接入部分与通知返回部分。接入部分即为传递参数等信息组合成超级链接,并用该链接来进行跳转。通知返回部分则是支付宝服务器对该笔订单处理完毕后,通知与返回该笔订单的详细信息到商户服务器,商 
户服务器接收到后,并对其进行数据处理。 
b) 以实物标准双接口ASP代码中的程序为例。 
i. 接入部分的页面文件包含:配置页alipay_Config.java、支付详细页alipay/alipayapi.jap、程序入口页index.jsp。 
ii. 通知返回部分的页面文件包含:支付完成后(支付宝处理完毕后)自动跳转回的自定义页面return_url.jsp、两方服务器间相互交互(肉眼无法见到的)通知页notify_url.jsp.
  ---------------------------------------------- 

二、 工作原理 
大家对结构部分已经有所了解,那么我们就开始分析具体的这个接口是如何运作的。 
a) 接入部分原理 
i. 第一步——选定参数信息: 
结合技术文档以及接口代码DEMO,选定传递给支付宝服务器的参数,以实物标准双接口为例。如必传项service、partner、seller_email、sign、sign_type、out_trade 
_no、price、subject、quantity、payment_type以及最少一组的物流信息参数三个logistics_type、logistics_fee、logistics_payment 
等,选填项body、discount、show_url等。 
ii. 第二步——排序: 
官方Demo已给 
iii. 第三步——加密: 
目前一般的加密方式是MD5,不论是哪种加密方式,要加密的信息是要传给支付宝的信息,且存在于技术文档中,而非自定义的变量名。对以上排序好的所有参数(不包括网关参数即:string gateway = "https://www.alipay.com/cooperate/gateway.do?" ;)以循环的方式,用‘&’字符拼接成一长串字符串(这里需要注意,所有的参数都是&字符来拼接的,拼接后直接再拼接安全校验码Key, 在程序中大家可看到,这个key是直接加到该字符串后面而没有用&字符 ),之后进行加密。得出的加密字符串集存储于sign这个参数中。 
iv. 第四步——拼接字符串成URL链接 
我们已经拿到了各个参数、参数所属的值以及加密得出的加密字符串,那么手上现在的所有参数信息的格式,应当都是一组一组的 service=”trade_create_by_buyer”这种格式的字符串,拼接的话,则依靠循环的方式遍历所有的这种字符串,因为这次的拼接是要成URL链接,所以之前排除在外的网关gaetway和加密类型参数sig 
n_type也都会被拼接进来,那么,连接的字符则用大家所熟知的字符’&’,就这样得出一个完整的URL链接地址,如: 

https://www.alipay.com/cooperate/gateway.do?s...3d199ba&sign_type=MD5 

该链接来自支付宝官方的技术文档“标准实物双接口技术文档” 
v. 第五步——自动跳转 
第四步中已经运算得出的URL链接字符串,我们则要让其活起来,那么活起来的方式就是——用程序调用它,也就是所谓的页面自动跳转。这样就能跳到支付宝的官方收银台页面。 
可以说,现在已经成功的把支付宝接口融合进了大家自己的网站中,且能够使用支付宝来进行付款了。 
b) 通知返回部分原理 
i. 专业术语 
通知返回是两个页面,即传递给支付宝时的notify_url参数所对应的页面文件(java的是notify_url.jsp)称之为通知页,传递 
给支付宝时的return_url参数所对应的页面文件(return_url.jsp)称之为返回页。 
ii. 通知返回原理 
1. 第一步——验证是否是支付宝服务器发来的请求: 
官方Demo有效验算法。
iii. 存在的区别 
1. 大家仔细阅读代码不难发现,在通知页中程序运行时,获取参数的方法是用POST方式,而返回页中程序运行时,获取参数的方法是用GET方式。由此可知一些基本的信息——返回页传递回来的参数信息是储存在URL链接 
里的,而通知页的参数信息是不在URL链接里,也能从中推断出二者在功能上的差异。 
2. 大家可看到通知页面比返回页中多一个环节,那就是Response.Write("success"); 
作用上不同的详细说明,大家可以看下面的第四部分。
------------------------------------------------------------------- 

三、 参数 
首先大家有个疑问,技术文档中的输入参数列表中给出了诸多参数,而手上拿到的代码里只写了一部分参数来进行传递信息,这究竟是为什么?那么我们先带着这个疑问往下看。 
以下讨论的参数不涵盖网关gateway、加密参数sign、加密类型sign_type,因为这些都是必须的。 
以实物标准双接口为例,可把参数看做几个功能部分组成 
a) 不可缺少的参数 
i. service服务参数,这个是用来区别这个接口是用的什么接口,所以绝对不能修改。 
ii. partner合作身份者ID、key安全校验码或称私钥这一组参数是签约合同生效后才能拿的到,partner是来鉴别是哪个商家与支付宝签约,而这个Key它如同钥匙般相当重要。 
iii. seller_email收款人支付宝账号,支付宝中有手机类型、电子邮件类型的支付宝账号是都可以用这个参数的。 
iv. subject在支付宝的收银台里是直接与商品名称关联在一起的,但是说的更准确些的话,这个参数是这笔交易的名称,因为这笔交易不一定只买一件商品。它的作用不仅是在收银台里可以清晰的显示出来,而且在支付宝的账 
户的交易明细的列表里,它也是排在第一列,由此可推测出,它有财务对账、作为交易查询的筛选条件等诸多作用。非常重要。 
v. out_trade_no技术文档中给出的是商户交易号(确保在商户系统中唯一),顾名思义这个就是我们大家自己网站的订单系统里的唯一订单号,而非支付宝的。这里需要强调的,这个订单号必须得是唯一的,如何唯一法?自己网站 
里订单系统的订单号是绝对唯一的吧,支付宝要求的唯一就是这个,为什么非要唯一?支付宝会根据订单号来判定这笔订单对于这个商家的所有交易中是否是唯一的。 
vi. price金额、quantity数量,这里设置有两种方式一种商品的单价金额,多个数量(即大于等于1)。另种是数量为1,金额代表总额,甚至是包含了运费。为什么大部分的客户要这么做?原因很简单,第一,购物车里的东西不一定是单纯的 
一件或者多件相同的商品,那么为商品设置金额时就有困难了,因此这里用总额是最好的,而数量就默认为1。第二,运费的设置很多客户是与各家快递公司签约、每件物品的快递费用也不尽相同,为了省去麻烦,在程序计算的 
时候干脆把运费也加进去。因此我们只需要记住一件事,这个price的金额就是所谓的总额了。 
vii. payment_type支付类型,没什么可说的直接写成1,无需改动。 
viii. 物流信息logistics_type、logistics_fee、logistics_payment这是一组物流信息,实物标准双接口中必须得至少有一组物流信息,也就是指这三个参数了,最多可有三组,哪三组呢?logistics_type_1、logistics_fee_1、 logistics_paymen 
t_1(第二组);logistics_type_2、logistics_fee_2、logistics_payment_2(第三组)。后两组为可选项。一般前面有说Price已经是总额了且包含了运费,那 
么这里物流运费就直接设置成0即可,即logistics_fee=”0”,其他两个的信息可参考技术文档来填写,因为要从技术文档中的枚举列表里来选择,所以绝不可乱填写。 
b) 可增加的有用参数 
i. 物流信息最多三组,最少一组,这已经在前部分有所提及,这里就不再细说。 
ii. _input_charset,当是UTF-8的编码格式时必须得用到且不允许为空的,即_input_charset=”utf-8” 
iii. notify_url、return_url,return_url代表支付完毕后可以自动从支付宝的官方页面跳转回来,notify_url这个是防止调单的首选最佳工具。 
iv. body,在支付宝收银台中的商品描述里显示,如果subject是订单名称的话,那么这个body则最准确的称之为订单描述,其实个人认为它作为备注之类的更为恰当。很多人都很郁闷支付宝为何不能像其他公司 
的接口有个自定义的参数来存放客户想要的东西,其实body也具有类似的这种功能,它不仅容纳的信息是所有参数里最大的,而且还是以字符串的形式储存,个人认为它其实也是非常重要的不可缺少的参数之一呢。 
v. discount折扣,顾名思义如果小于0,则是用原金额Price*quantity+(discount),实际金额便比原总额小了。现在有些商户有支付宝的优惠卷,而优惠卷的用途也是在这个参数中体现,具体做法与前 
面无异。 
vi. show_url商品展示地址,这个链接的作用是在支付宝收银台的商品链接旁边有个下划线“详情”的链接,而点链接弹出的一个新页面便是这个商品展示地址的页面。 
vii. 收货信息receive_name、receive_address、receive_zip、receive_phone、 receive_mobile,这些信息若也设置为传递给支付宝的参数之一的话,那么在支付宝收银台点选下一步的时候,本该出现的填写收货信息页面不见踪影,而直接跳到了收货信息页面的下一个页面去了。很多商户在自己的网站的购物 
流程中都有一个填写收货信息的选项卡,为了省去到支付宝收银台中还要填写一次收货信息的麻烦,那么这些收货信息的参数就派上用场了。值得注意的是,收货人姓名和地址是必填项,不然还是会出现收货信息填写页。 
viii. buyer_email买家支付宝账号,这个设置好后呈现的效果便是,原本是空的支付宝账号的输入框此时已经有个支付宝账号在里面放置。 
c) 剩下的参数无需理会 

整个实物标准双接口的参数介绍完毕,那么其他接口的参数还要介绍吗?大家从上面分析得出的东西对比技术文档的参数列表是否看出什么来了? 

1、 参数列表的最后一列叫“可空”,N代表不允许为空,Y代表允许为空,结合上面的不可缺少参数与增加的有用参数来进行比较,不难发现,不可缺少的参数全是为N的。 
2、 有些为Y的参数有一组,例如buyer_email、buyer_id,凡是遇到这种的一般都是二可选一也可都不选,或是二必选一。举例说明:二必选一的是seller_email、seller_id,二选一的 
是buyer_email、buyer_id。 
所有的接口的参数如此分析就能判断出哪些是重要参数哪些可不要,结合技术文档与程序接口来研究就能一目了然。 
-------------------------------------------------------- 

四、 通知返回 
a) 返回页 
传递给支付宝时的return_url参数所对应的页面文件。 
具备的属性: 
1、支付接口中买家的购买流程已经走到支付宝里且支付宝提示支付成功时,页面会自动跳转回自身网站的这个页面里来。 
2、同步的,无时差 
3、获得参数的方法是用get方式获取。 
4、不论跳转回来程序判断是真还是假(if(sign = mysign and responseTxt = true))只跳转回来一次,不重复。 
5、这个并不是支付宝服务器调用了该页面,而是通过与组合拼接各参数形成的URL链接原理等同,拼接出来的URL链接,之后程序上做自动跳转。 
6、基于5的原因,该页面的程序调试可不必在服务器上而是本机上调试、运行。 
b) 通知页 
传递给支付宝时的notify_url参数所对应的页面文件 
具备的属性: 
1、这个通知页就是被支付宝调用才能启动的。 

2、服务器间的互动,不像返回页肉眼可以看到,这个是看不到的。 

//获取支付宝POST过来反馈信息  
        Map<String,String> params = new HashMap<String,String>();  
        Map requestParams = request.getParameterMap();  
        for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext();)   
            String name = (String) iter.next();  
            String[] values = (String[]) requestParams.get(name);  
            String valueStr = "";  
            for (int i = 0; i < values.length; i++)   
                valueStr = (i == values.length - 1) ? valueStr + values[i]  
                        : valueStr + values[i] + ",";  
              
            //乱码解决,这段代码在出现乱码时使用。如果mysign和sign不相等也可以使用这段代码转化  
            //valueStr = new String(valueStr.getBytes("ISO-8859-1"), "gbk");  
            params.put(name, valueStr);  
          
          
        //获取支付宝的通知返回参数,可参考技术文档中页面跳转同步通知参数列表(以下仅供参考)//  
        //商户订单号  
  
        String out_trade_no = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"),"UTF-8");  
  
        //支付宝交易号  
  
        String trade_no = new String(request.getParameter("trade_no").getBytes("ISO-8859-1"),"UTF-8");  
  
        //交易状态  
        String trade_status = new String(request.getParameter("trade_status").getBytes("ISO-8859-1"),"UTF-8");  
  
        //获取支付宝的通知返回参数,可参考技术文档中页面跳转同步通知参数列表(以上仅供参考)//  
  
        if(AlipayNotify.verify(params))//验证成功  
            //  
            //请在这里加上商户的业务逻辑程序代码  
  
            //——请根据您的业务逻辑来编写程序(以下代码仅作参考)——  
              
            if(trade_status.equals("TRADE_FINISHED"))//交易完成  
                //更新订单状态  
                  
             else if (trade_status.equals("TRADE_SUCCESS"))  
                //更新订单状态<pre name="code" class="java">  
//——请根据您的业务逻辑来编写程序(以上代码仅作参考)——out.println("success"); //请不要修改或删除//else//验证失败out.println("fail");  
3、获得参数的方法是用POST方式获取。 
4、支付宝中的该笔交易存在,且该笔交易状态发生了变更,就会被调用。 
5、被调用程序判断(if(sign = mysign and responseTxt = true)),若我们自己在该判断中有做程序编写,成功则不再被调用,不成功则会反复被调用。 
6、异步的,第一次收到订单信息(以下都称之为“通知”)是与返回页近乎等同或等同的同步时间,在判断不成功的情况下,会收到第二次第三次等次数的通知,时间间隔从最先的一两分钟,到后面的几个小时。失效时间是4 
8小时。 
7、基于6的原因,该页面的程序调试必须在服务器上调试、运行。 
8、程序编写时必须采用程序执行成功,才写页面response.Write(“success”);,不成功则写页面response.Write(“fail”); 支付宝根据success来判定是否要重新再次发送通知。 

9、该页面的Html页面中必须是空白、无任何Html标签、无任何空格、不允许做页面跳转。 


c) 在支付宝的众多接口中,不是所有的接口都拥有通知页与返回页的。 
有的接口只有返回页;有的接口有通知页且用XML格式的内容显示在当前页面中;有的没有通知页也没有返回页仅仅只以XML格式的内容显示在当前页面中。所以,我们要根据各接口的技术文档与程序实例来做相应的数据处 
理。 
d) 大家这里存在一个疑问,一般大家的做法都是把数据库更新些在返回页中,但是很多情况下出现了订单不同步即掉单现象。这是为什么? 
答:返回页是当前页面自动跳转的,这虽然跳转的反应速度不错,但人的手动关闭该页面操作绝对可以使之在没有跳转回来之前就关掉了该页面,此时原本该数据库更新的程序并没有被启动,这样直接导致了掉单,所以一般大商 
户,尤其是网络游戏行业的即时到帐充值的技术做法是:返回页中有订单处理程序,通知页中也有,当返回页中的订单没做过处理时,通知页中的数据处理程序便启动;这样即可近乎100%解决掉单问题(还有种掉单原因是大家自己的服务器出现问题,比如MS3XML.DLL问题,这个问题至今没有什么可以解决的办法,只能重装或是更换服务器,也有的服务器因为中毒才导致的)。本文来源于 http://www.k686.com/ 
------------------------------------------------- 

五、 调试 
接入部分做好了,通知返回部分也做好了,那么开始调试吧。 
调试也分成两大部分来做。 
a) 部分网站用了框架模式,但这个并不适用支付宝的接口程序,因此绝对不能把支付宝的接口页面置于整个网站的框架之下。 
b) 确定好要用POST还是GET方式来传递参数,二者不能混用。由于有些网站中不一定只有一个接口入口,所以整个网站都必须保持一致性,不能这个接口用POST,那个接口用GET,这样直接导致后续出现一系列连查找 
原因都极其困难的现象。 
c) 接入部分的调试工作,则是输入支付宝要求的格式的值,如subject、body的值不允许有非法字符、金额格式必须是小数点后两位数或是正整数且不是金额格式,以及非常重要的一个原则,传递的参数要么不传递这个参数(即传递的众多参数中,这个参数完全不存在),要么这个参数不允许为空。很多人在调试时支付出现一系列“调试错误”有很大的一部分原因就是参 
数的设置存在问题。 
d) 编码格式一定要确认再确认,在支付时直接出现“调试错误,SIGN不对”只有两种原因,一是C部分已提到的参数的设置问题,另一个便是这个编码格式的问题。编码格式是非常重要的,绝对不能这个地方用GBK,另个地方用utf-8。 
e) 通过接口走一次真实的操作,若是支付接口,则走一笔真实的交易,金额则是0.01元(支付宝是没有测试环境的,所以请老实的使用自己签约的号去走真实交易),不要觉得很麻烦,也不要把这个工作交个经理或者你的老板 
来做,因为它直接关系到你后续的操作步骤与调试的顺畅程度。 
f) 返回部分在本机电脑上就可以调试完毕,之前有提到不要把支付测试工作交给自己以外的其他人,这里就可以得到充分的说明,不论是哪种语言都拥有自己风格的单步监控程序代码的能力,返回部分就要一步一步监控程序的执行,确保1、是否执行到了“mysign == sign && responseTxt == "true"”,这个IF语句的判断;2、是否进入了这个语句里而不是else里;3、数据库更新程序是否执行成功,而不是卡着不动了;4、数据库更新完毕后,程序是否走完。基本出现问题的地方就在第一步,所以不要 
觉得奇怪为什么掉单? 
g) 通知页的调试,这个调试就比较麻烦了,首先这个支付宝接口已经完成且放在了服务器上,别人可以通过互联网来进行支付;其次,要把通知页中的“写日志”程序启动起来,日志内容主要记录trade_status、tr 
ade_no、out_trade_no、price、sign、mysign、responseTxt等。一般出现的原因依旧是“mysign == sign && responseTxt == "true"”这个判断上不被通过。 
具体检测方式: 
1、直接用互联网访问http://www.xxx.com/alipay/notify_url.asp 
访问是否能够访问得到,且显示"fail"的字眼,其他如空白或是其他程序错误提示等内容,均属程序执行出错。 
2、程序是否执行到,sign=mysgin and responseTxt = "true"这个判断中,如果执行到这个判断时跳到ELSE的判断语句去了,则表示您的接口程序在支付时传递的参数信息或是您的编码格式、合作身份者ID与安全校验码的设置存在问题。 
3、程序已经执行到sign=mysgin and responseTxt = "true"这个判断中,却没有执行到response.Write("success")这句话,说明您自己编写进去的程序代码执行出错,请检查。 

---------------------------------------------------------- 

六、 其他 
a) 有些接口,例如支付的接口,是支持POST或者GET方式传递参数的。 
i. POST传递方式: 
这里需要注意的地方是:<form action=” aliay_url” …>中action的值是网关+编码格式参数,即https://www.alipay.com/cooperate/gateway.do? _input_charset=utf-8,GBK的编码格式可以为:https://www.alipay.com/cooperate /gateway.do?。 
ii. GET传递方式: 
是用&字符来连接起来的一长串URL链接字符串,通过自动跳转不是<form action=” aliay_url” …>的方式来存放,而是用Response.Redirect(aliay_url)方式来进行跳转。

以上是关于支付宝异步通知notify_url与return_url的主要内容,如果未能解决你的问题,请参考以下文章

支付宝接口使用文档说明 支付宝异步通知(notify_url)与return_url

支付宝异步通知notify_url与return_url

支付宝异步通知notify_url与return_url

检查支付宝异步通知是否正确

支付宝接口 notify_url.php和return_url.php这两个页面应该怎么写

QGC 支付宝无法异步通知及异步通知常见问题注意事项