时间:2024-08-31 点击: 次 来源:网络 添加者:佚名 - 小 + 大
大家想必都有这种困惑——拿到支付宝的接口代码后,尽管里面的程序有注释,接口代码包中也附有开发说明,但还是不知道该如何入手。这不难想象是什么原因,因为自己并不了解这个接口的工作原理是什么? 那么这篇文章就是要向大家全面展示关于支付宝接口的所有东西,以便大家能快速上手把接口接入自己的项目中,也能帮助那些已经对支付宝接口有所了解的程序开发者们更了解支付宝的一些通用规则、特殊用途等。 正题开始—— 一、 结构 a) 一般由两部分组成,接入部分与通知返回部分。接入部分即为传递参数等信息组合成超级链接,并用该链接来进行跳转。通知返回部分则是支付宝服务器对该笔订单处理完毕后,通知与返回该笔订单的详细信息到商户服务器,商 户服务器接收到后,并对其进行数据处理。 b) 以实物标准双接口asp代码中的程序为例。 i. 接入部分的页面文件包含:配置页alipay_config.asp、方法详细页alipay/alipay_payto.asp、程序入口页index.asp以及md5加密方法类页alipayto/alipay_md5.asp。 ii. 通知返回部分的页面文件包含:方法详细页alipay/alipay_payto.asp、md5加密方法类页alipayto/alipay_md5.asp、支付完成后(支付宝处理完毕后)自动跳转回的自定义页面return_alipay_notify.asp、两方服务器间相互交互(肉眼无法见到的)通知页alipay_notif y.asp。 这里大家可以一目了然,md5加密方法类与方法详细页不论是哪部分都有被调用,因此这两个文件可视为核心代码部分,若想理解接口的工作原理则要从该部分入手。 c) 以实物标准双接口的asp.net c#语言代码程序为例: i. 接入部分的页面文件包含:无需更改的alipay的类文件app_code/alipay.cs及入口页面文件default.aspx ii. 通知返回部分的页面文件包含:两方服务器间相互交互(肉眼无法见到的)通知页alipay_notify.aspx、支付完成后(支付宝处理完毕后)自动跳转回的自定义页面alipay_return.aspx、 无需更改的alipay的类文件app_code/alipay.cs 这个架构是否更容易理解了?没错,核心部分的运算过程就在alipay.cs这个文件中。 二、 工作原理 大家对结构部分已经有所了解,那么我们就开始分析具体的这个接口是如何运作的。 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等。 以asp.net c#语言代码程序为例: string service = "trade_create_by_buyer"; string seller_email = "aaaa@126.com"; string sign_type = "md5"; string key = "********************************"; string partner = "2088************"; string _input_charset = "utf-8"; string show_url = " string out_trade_no = txtorderno.text.trim(); string subject = txtsubject.text.trim(); string body = txtbody.text.trim(); string price = txtprice.text.trim(); string quantity = txtqua.text.trim(); string logistics_type = "post"; string logistics_fee = txtpost.text.trim(); string logistics_payment = "buyer_pay"; string notify_url = " string return_url = " ii. 第二步——排序: 把这些参数的变量名(即技术文档里给出的变量名,以这种方式组合:service=”trade_create_by_buyer”作为一串字符串)按从a到z的顺序依次排序。以asp.net c#语言代码程序为例,该功能在alipay.cs类中;以asp代码中的程序为例,该功能在alipayto/alipay_payto.asp文件中。 iii. 第三步——加密: 目前一般的加密方式是md5,不论是哪种加密方式,要加密的信息是要传给支付宝的信息,且存在于技术文档中,而非自定义的变量名。对以上排序好的所有参数(不包括网关参数即:string gateway = " iv. 第四步——拼接字符串成url链接 我们已经拿到了各个参数、参数所属的值以及加密得出的加密字符串,那么手上现在的所有参数信息的格式,应当都是一组一组的service=”trade_create_by_buyer”这种格式的字符串,拼接的话,则依靠循环的方式遍历所有的这种字符串,因为这次的拼接是要成url链接,所以之前排除在外的网关gaetway和加密类型参数sig n_type也都会被拼接进来,那么,连接的字符则用大家所熟知的字符’&’,就这样得出一个完整的url链接地址,如: 该链接来自支付宝官方的技术文档“标准实物双接口技术文档” v. 第五步——自动跳转 第四步中已经运算得出的url链接字符串,我们则要让其活起来,那么活起来的方式就是——用程序调用它,也就是所谓的页面自动跳转。这样就能跳到支付宝的官方收银台页面。 可以说,现在已经成功的把支付宝接口融合进了大家自己的网站中,且能够使用支付宝来进行付款了。 b) 通知返回部分原理 i. 专业术语 通知返回是两个页面,即传递给支付宝时的notify_url参数所对应的页面文件(asp.net的是alipay_notify.aspx、asp的是alipay_notify.asp)称之为通知页,传递 给支付宝时的return_url参数所对应的页面文件(asp.net的是alipay_return.aspx、asp的是return_alipay_notify.asp)称之为返回页。 ii. 通知返回原理 1. 第一步——验证是否是支付宝服务器发来的请求: a) 以asp程序代码为例: alipaynotifyurl = " alipaynotifyurl = alipaynotifyurl &"partner=" & partner & "¬ify_id=" & request("notify_id") set retrieval = server.createobject("msxml2.serverxmlhttp.3.0") retrieval.setoption 2, 13056 retrieval.open "get", alipaynotifyurl, false, "", "" retrieval.send() responsetxt = retrieval.responsetext set retrieval = nothing 得到的便是responsetxt的值,这是下面的步骤要用到的。 b) 以asp.net c#程序代码为例: //获取远程服务器atn结果,验证是否是支付宝服务器发来的请求 public string get_http(string a_strurl, int timeout) { string strresult; try { httpwebrequest myreq = (httpwebrequest)httpwebrequest.create(a_strurl); myreq.timeout = timeout; httpwebresponse httpwresp = (httpwebresponse)myreq.getresponse(); stream mystream = httpwresp.getresponsestream(); streamreader sr = new streamreader(mystream, encoding.default); stringbuilder strbuilder = new stringbuilder(); while (-1 != sr.peek()) { strbuilder.append(sr.readline()); } strresult = strbuilder.tostring(); } catch (exception exp) { strresult = "错误:" + exp.message; } return strresult; } 调用部分: string alipaynotifyurl = " string partner = "2088************"; alipaynotifyurl = alipaynotifyurl + "&partner=" + partner + "¬ify_id=" + request.form["notify_id"]; //获取支付宝atn返回结果,true是正确的订单信息,false 是无效的 string responsetxt = get_http(alipaynotifyurl, 120000); 得到的便是responsetxt的值,这是下面的步骤要用到的。 2. 第二步——排序: 该部分的排序的原理与“接入部分”的原理“排序步骤”一样,值得注意的是,这里的参数是支付宝通知返回时,传回来的订单信息的各种参数以及值。 3. 第三步——加密: 该部分的加密原理与“接入部分”的原理“加密步骤”一样,依然值得注意的部分是加密的参数信息,这些参数信息是来源于上面一步骤排序好后的参数拼接起来的字符串来加密的。 4. 第四步——判断: 上面我们有得到加密的结果(命名为mysign吧)、检验是否是支付宝发来的消息的正确性responsetxt、以及通过post或get的方式得到的sign参数的值,那么这个判断的含义便是通知返回里最重要 的部分了,因为它是来检验下面的程序是否执行我们的数据处理的。如何判断呢?各语言程序代码中,都是把加密得出的结果mysign与从支付宝那或得到的sign的值进行比较,并且还要让reponsetxt这个的 值要等于true,这样才达到验证成功。值得注意的是,大家都有遇到过这种事,支付部分即接入部分的确是做好了,但为什么无法与支付宝的交易信息同步,出现的问题就在这个判断上没有成功,下面的第五部分则会详细说 明。 5. 第五步——自身网站的数据处理 终于判断成功了,程序已经执行到了这里。各语言程序代码的这块地方的注释都写着“更新自己数据库的订单语句”或是“这里可以指定你需要显示的内容”。如字面上的意思,这块地方就是要我们大家来对这笔交易信息进行数 据处理,即编写程序。这个说法大概专业了点,简单易懂的讲法便是,支付宝的交易成功的信息和其他的一切交易状态,自己的网站也能够对这笔订单同步起来,即支付宝里这笔订单的交易状态是“买家已付款等待卖家发货”, 那么自己网站里显示的这笔状态也因如此,那么就应当在这里面写下诸如: if (request.form["trade_status"] == "wait_seller_send_goods")// 判断支付状态_买家付款成功,等待卖家发货(文档中有枚举表可以参考) { //更新自己数据库的订单语句,请自己填写一下 string strorderno = request.form["out_trade_no"];//订单号 string strprice = request.form["price"];//金额 string sql = "update order_table set order_status = ‘买家已付款,等待卖家发货’ where order_no = " + strorderno; update(sql); } 等数据库处理代码。 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_payment_1(第二组);logistics_type_2、logistics_fee_2、logist ics_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、服务器间的互动,不像返回页肉眼可以看到,这个是看不到的。 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# asp.net实物标准双接口代码为例: if (mysign == sign && responsetxt == "true") { if (request.form["trade_status"] == "wait_buyer_pay")// 判断支付状态_等待买家付款(文档中有枚举表可以参考) { //更新自己数据库的订单语句,请自己填写一下 } else if (request.form["trade_status"] == "wait_seller_send_goods")// 判断支付状态_买家付款成功,等待卖家发货(文档中有枚举表可以参考) { //更新自己数据库的订单语句,请自己填写一下 string strorderno = request.form["out_trade_no"];//订单号 string strprice = request.form["price"];//金额 string sql = "update order_table set order_status = '买家已付款,等待卖家发货' where order_no = @out_trade_no"; update(sql,para); } else if (request.form["trade_status"] == "wait_buyer_confirm_goods")// 判断支付状态_卖家已发货等待买家确认(文档中有枚举表可以参考) { //更新自己数据库的订单语句,请自己填写一下 string strorderno = request.form["out_trade_no"];//订单号 string strprice = request.form["price"];//金额 string sql = "update order_table set order_status = '卖家已发货,等待买家确认收货' where order_no = @out_trade_no"; update(sql, para); } else if (request.form["trade_status"] == "trade_finished")// 判断支付状态_交易成功结束(文档中有枚举表可以参考) { //更新自己数据库的订单语句,请自己填写一下 string strorderno = request.form["out_trade_no"];//订单号 string strprice = request.form["price"];//金额 string sql = "update order_table set order_status = '交易成功' where order_no = @out_trade_no"; update(sql, para); } else { //更新自己数据库的订单语句,请自己填写一下 } response.write("success"); } else { response.write("fail"); } c) 在支付宝的众多接口中,不是所有的接口都拥有通知页与返回页的。有的接口只有返回页;有的接口有通知页且用xml格式的内容显示在当前页面中;有的没有通知页也没有返回页仅仅只以xml格式的内容显示在当前页面中 。所以,我们要根据各接口的技术文档与程序实例来做相应的数据处理。 d) 大家这里存在一个疑问,一般大家的做法都是把数据库更新些在返回页中,但是很多情况下出现了订单不同步即掉单现象。这是为什么?返回页是当前页面自动跳转的,这虽然跳转的反应速度不错,但人的手动关闭该页面操作绝 对可以使之在没有跳转回来之前就关掉了该页面,此时原本该数据库更新的程序并没有被启动,这样直接导致了掉单,所以一般大商户,尤其是网络游戏行业的即时到帐充值的技术做法是:返回页中有订单处理程序,通知页中也 有,当返回页中的订单没做过处理时,通知页中的数据处理程序便启动;这样即可近乎100%解决掉单问题(还有种掉单原因是大家自己的服务器出现问题,比如ms3xml.dll问题,这个问题至今没有什么可以解决的办法,只能重装或是更换服务器,也有的服务器因为中毒才导致的。)。 五、 调试 接入部分做好了,通知返回部分也做好了,那么开始调试吧。 调试也分成两大部分来做。 a) 部分网站用了框架模式frame,但这个并不适用支付宝的接口程序,因此绝对不能把支付宝的接口页面置于整个网站的框架之下。 b) 确定好要用post还是get方式来传递参数,二者不能混用。由于有些网站中不一定只有一个接口入口,所以整个网站都必须保持一致性,不能这个接口用post,那个接口用get,这样直接导致后续出现一系列连查找 原因都极其困难的现象。 c) 接入部分的调试工作,则是输入支付宝要求的格式的值,如subject、body的值不允许有非法字符、金额格式必须是小数点后两位数或是正整数且不是金额格式(即$123.00),以及非常重要的一个原则,传递的参数要么不传递这个参数(即传递的众多参数中,这个参数完全不存在),要么这个参数不允许为空。很多人在调试时支付出现一系列“调试错误”有很大的一部分原因就是参 数的设置存在问题。 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"”这个判断上不被通过。 六、 其他 a) 有些接口,例如支付的接口,是支持post或者get方式传递参数的。 i. post传递方式: 这里需要注意的地方是:<form action=” aliay_url” …>中action的值是网关+编码格式参数,即 ii. get传递方式: 是用&字符来连接起来的一长串url链接字符串,通过自动跳转不是<form action=” aliay_url” …>的方式来存放,而是用response.redirect(aliay_url)方式来进行跳转 原文链接:https://blog.csdn.net/wangliqiang1014/article/details/7358542 |
上一篇:ASP中只有UrlEncode,没有Urldecode问题的解决方法?
下一篇:没有了