微信小程序支付的主要逻辑集中在后端,前端只需要携带支付所需的数据并请求后端接口,然后根据返回的结果处理相应的成功或失败。本文后端使用php,重点介绍整个支付过程和一些细节。所以用其他后端语言的朋友如果需要可以看看。很多时候开发的要求和相应问题的解决真的要跳出语言语法层面,从系统和流程的角度去考虑。
一.付款
付款主要分为几个步骤:
前端使用支付所需的数据(商品id、购买数量等)发起支付请求。)
后端收到支付请求后,对支付数据进行处理,然后携带处理后的数据请求微信服务器的支付统一下单接口。
后端接收前面请求微信服务器返回的数据,再次处理,然后返回前端,这样前端就可以开始支付了。
前端付款操作
前端支付完成后,微信服务器会向后端发送支付通知(也就是微信会告诉你客户已经支付),后端会根据这个通知确定支付完成,然后在支付完成后采取相应的动作,比如修改订单状态,添加交易日志等等。
从这几个步骤可以看出,后端的主要作用是将支付所需的数据传输到微信服务器,然后根据微信服务器的响应来确定支付是否完成。
这个过程挺好理解的。说白了,前端是客户,后端是店铺,微信服务器的统一点餐界面就像收银台。告诉顾客我是谁,我现在出多少钱就给你买多少。只要告诉收银员店主要多少钱,你就准备收钱了。收银员收到钱后会告诉店家我收到钱了。请给他一些东西。下面将详细解释每个步骤的具体实现。
1.前端付款请求
前端支付请求只是携带支付所需的数据,如用户ID、支付金额、支付订单ID等。* *与你的业务逻辑有关* *或者* *与下一步请求微信服务器支付统一点餐接口所需数据有关。使用微信小程序的wx.request()请求后台支付接口。
2.后端请求微信服务器
后端收到前端发送的支付请求后,可以进行相关验证,比如判断用户是否有问题,支付金额是否正确等等。
在验证没有问题,可以向微信服务器申请支付后,后端需要使用微信规定的数据格式,请求微信统一的支付下单接口。
微信指定的请求数据:
这需要更多的代码实现。因为需要的数据量很大,而且需要加密,以XML格式发送。首先,以下数据是使用小程序支付时必须提供给微信服务器的参数。
子视图的Appid。大概没有一个写小程序的人不知道这一点。。。
标识用户openid。即用户的applet ID。在我的上一篇博客中,我解释了如何获得它。
商户mch_id。成功申请微信支付商户认证后,有
商家订单编号out _ trade _ no。商家为此付款生成的订单编号
总计_费用金额_费用。订单的总金额,很重要的一点是单位是积分,所以要特别注意。
微信服务器回调通知接口地址notify_url。微信确认钱到账后,会多次发信息到这个地址,告诉你客户已经交钱了。你需要给微信回消息,表明你已经收到通知。。该地址不能有端口号,并且必须能够直接接受POST方法请求。
贸易类型。微信小程序把这个值作为JSAPI来支付。
商品信息体。像“腾讯-游戏”这种形式
IP地址spbill_create_ip。终端的IP地址,即支付请求的IP地址。
随机字符串nonce_str。需要由后端随机生成的字符串来确保数据安全。微信要求不超过32位。
签名。使用上述所有参数来处理加密以生成签名。(具体处理方法见下面的代码,可以直接重用。)
以上数据全部处理完毕后,数据将以XML格式排序,以POST方式发送到微信支付的统一下单接口。
3.后端接受微信服务器返回的数据。
微信服务器收到支付数据后,如果数据没有问题,就会返回相应的数据进行支付,尤其是名为prepay_id的数据字段,需要返回给前端,前端才能继续支付。
所以后端收到微信服务器返回的数据后,需要进行相应的处理,最终返回给前端的数据如下:
Appid就不用说了。
时间戳当前时间戳
非中心随机字符串
Package就是上面说的prepay_id,但是要记住“prepay_id= prepay_id_item”这样的格式。否则会造成错误。
SignType加密方法,一般为MD5。
Pay对上述数据进行相应的处理和加密。
至此,后端支付接口已经完成了接收前端支付请求并返回前端支付所需数据的功能。
4.前端发起的支付
前端收到返回数据后,使用wx.requestPayment()请求发起支付。这个API所需的对象参数值是我们在上一步中返回的数据。
5.后端接受微信服务器回调。
前端支付完成后,微信服务器确认支付已完成。将向第一步中设置的回调地址发送通知。后端接收回调接口收到通知后,可以判断支付是否完成,从而决定后续动作。
需要注意的是,收到微信服务器的回拨通知后,根据通知的result_code字段判断支付是否成功。后端收到成功通知后,需要返回成功数据通知微信服务器收到回调通知。否则微信服务器会一直给后端发消息。另外,微信的通知是XML格式发送的,你在接受的时候要注意。
这是微信大致的支付流程。下面是PHP语法的微信支付类,可以按照上面的步骤介绍,加深理解。当你需要付费的时候,你可以简单的传入参数来实例化这个类,然后调用这个类的pay方法。
//微信支付类Classweixinpay {//= = = = = = =【基本信息设置】= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =填写你的appid。微信公众平台中受保护的$ APPSECRET = secret//接受者ID,标识受保护$ MCHID = & # 03911111111';//商户id //商户支付密钥Key protected $ KEY = & # 039192006250 b4c 09247 EC 02 edce 69 F6 a 2d & # 039;;//回调通知接口受保护$ APPURL = & # 039https://smart.afei.com/receivesuc';//交易类型受保护$ TRADETYPE = & # 039JSAPI & # 039;//商品类型信息受保护$ BODY = & # 039wx/book & # 039;;//微信支付类{$ this->的构造函数function _ _ construct ($ openid,$ outradeno,$ total fee);openid = $ openid//用户唯一ID $ this ->:outTradeNo = $ outTradeNo;//商品编号$ this ->;totalFee = $ totalFee//总价}//公共函数Pay(){ $ result = $ this ->;微信支付类weixinapp()暴露的支付接口;返回$ result}//处理微信统一下单接口私有函数Weixin App(){ $ unified order = $ this ->返回的支付相关数据;unified order();$ parameters = array(& # 039;appId & # 039= & gt$ this -& gt;APPID,//小程序ID & # 039时间戳& # 039;= & gt''。时间()。'',//时间戳& # 039;非埃斯特& # 039;= & gt$ this -& gt;CreateNoncestr(),//随机字符串& # 039;套餐& # 039;= & gt'prepay _ id = & # 039。$ unified order[& # 039;prepay _ id & # 039],//数据包& # 039;signType & # 039= & gt'MD5 & # 039//签名方法);$ parameters[& # 039;paySign & # 039]= $ this -& gt;get sign($ parameters);返回$ parameters}/* *请求微信统一下单接口*/私有函数统一下单(){ $ parameters = array(& # 039;appid & # 039= & gt$ this -& gt;APPID,//小程序id & # 039mch _ id & # 039= & gt$ this -& gt;MCHID,//商家id & # 039spbill _ create _ ip & # 039= & gt$ _服务器[& # 039;远程_ ADDR & # 039;],//终端ip & # 039通知_网址& # 039;= & gt$ this -& gt;Url,//通知地址& # 039;nonce _ str & # 039= & gt$ this -& gt;CreateNoncestr(),//随机字符串& # 039;out _ trade _ no & # 039= & gt$ this -& gt;OutTradeNo,///商户订单号& # 039;总费用& # 039;= & gtfloat val($ this -& gt;TotalFee),//总金额& # 039;open _ id & # 039= & gt$ this -& gt;Openid,//用户openid & # 039trade _ type & # 039= & gt$ this -& gt;TRADETYPE,//交易类型& # 039;正文& # 039;= & gt$ this -& gt;体,//商品信息);$ parameters[& # 039;标志& # 039;]= $ this -& gt;get sign($ parameters);$ XML data = $ this -& gt;arrayToXml($ parameters);$ XML _ result = $ this -& gt;postmlcurl($ XML data,& # 039;https://api.mch.weixin.qq.com/pay/unifiedorder',60岁);$result = $this->XML to array($ XML _ result);返回$ result}//数组到字符串方法受保护的函数ArrayToXML($ arr){ $ XML = " & lt;xml & gt";foreach($ arr as $ key = & gt;$ val){ if(is _ numeric($ val)){ $ XML。= & quot& lt"。$key。"& gt"。$瓦尔。"& lt/& quot;。$key。"& gt";}else{ $xml。= & quot& lt"。$key。"& gt& lt![CDATA[& quot;。$瓦尔。"]]& gt;& lt/& quot;。$key。"& gt";} } $xml。= & quot& lt/XML & gt;";返回$ xml}受保护的函数xmlto array($ XML){ $ array _ data = JSON _ decode(JSON _ encode(SimpleXML _ load _ string($ XML,& # 039;SimpleXMLElement & # 039,LIBXML_NOCDATA)),true);返回$ array _ data}//发送xml请求方法privatestatic函数postxmlurl($ XML,$ URL,$ second = 30){ $ ch = curl _ init();//设置超时curl _ setopt ($ ch,curl opt _ timeout,$ second);curl_setopt($ch,CURLOPT_URL,$ URL);curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,FALSE);curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,FALSE);//严格检查//设置头curl _ setopt ($ ch,curl opt _ header,false);//要求结果为字符串并输出到屏幕curl _ setopt ($ ch,curl opt _ return transfer,true);//post提交方法curl _ setopt ($ ch,curl opt _ post,true);curl_setopt($ch,CURLOPT_POSTFIELDS,$ XML);curl_setopt($ch,CURLOPT_CONNECTTIMEOUT,20);curl_setopt($ch,CURLOPT_TIMEOUT,40);set _ time _ limit(0);//运行curl $ data = curl _ exec($ ch);//返回结果if($ data){ curl _ close($ ch);返回$ data} else { $ error = curl _ errno($ ch);curl _ close($ ch);抛出新的WxPayException(& quot;Curl错误,错误代码:$ error & quot);}}/* *签署要发送到微信统一订购接口的数据*/Protected Function Get Sign($ obj){ foreach($ objas $ k = >;$ v){ $ Parameters[$ k]= $ v;}//签名第一步:将参数ksort($Parameters)按字典顺序排序;$ String = $ this -& gt;formatBizQueryParaMap($ Parameters,false);//签名第二步:在字符串后添加key $ string = $ string。"& ampkey = & quot。$ this -& gt;关键;//签名第三步:MD5加密$ String = MD5($ String);//签名第四步:所有字符大写$ result _ = strtop($ string);返回$ result _;}/* *排序和格式化参数方法。您需要使用*/protected函数formatbizqueryparamap ($ paramap,$ urlencode){ $ buff = " & quot;;ksort($ paraMap);foreach($ paraMap as $ k = & gt;$ v){ if($ urlencode){ $ v = urlencode($ v);} //$buff。= strtolower($k)。"= & quot。v . & quot& amp";$buff。= $ k。& quot;= & quot。v . & quot& amp";} $ reqParif (strlen($buff)>0) { $reqPar = substr($buff,0,strlen($ buff)-1);} return $ reqPar}/* *生成随机字符串的方法*/Protected Function CreateNocestr($ length = 32){ $ chars = " abcdefghijklmnopqrstuvwxyz 0123456789 & quot;;$ str = & quot";for($ I = 0;$ i & lt$长度;$i++ ) { $str。= substr($chars,mt_rand(0,strlen($chars)-1),1);} return $ str}}
评论前必须登录!
注册