Erlang服务端与微信登录和微信支付接口的交互

      Erlang服务端与微信登录和微信支付接口的交互

 

最近因为项目需要做微信支付的功能。分享下心得和代码(本人测试成功)。因为erlang的开源资源很少,也没找到合适的方法解析微信开放平台发送的XML数据。所以将自己造的轮子分享下。下面详细介绍下erlang后端和微信开发平台交互的步骤。全是自己一字一字码上去的,转载请注明转自Zmyths 加地址,谢谢。

 

1.  先看看微信开放平台的官方开发文档:https://open.weixin.qq.com/

 如图:


官方的微信登录和微信支付的API,给定的参数很详细。

 

2. 微信支付API的文档链接:

https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_1

微信登录API的文档链接:

https://open.weixin.qq.com/cgibin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419317853&token=&lang=zh_CN

 

3. http的几种请求方式

 

Http定义了与服务器交互的不同方法,最基本的方法有4种,分别是GET,POST,PUT,DELETE。URL全称是资源描述符,我们可以这样认为:一个URL地址,它用于描述一个网络上的资源,而HTTP中的GET,POST,PUT,DELETE就对应着对这个资源的查,改,增,删4个操作。到这里,大家应该有个大概的了解了,GET一般用于获取/查询资源信息,而POST一般用于更新资源信息。

 

Get 和Post区别:

简单说:Get是向服务器发索取数据的一种请求,而Post是向服务器提交数据的一种请求

Get是获取信息,而不是修改信息,类似数据库查询功能一样,数据不会被修改Get请求的参数会跟在url后进行传递,请求的数据会附在URL之后,以?分割URL和传输数据,参数之间以&相连,XX中的XX为该符号以16进制表示的ASCII,如果数据是英文字母/数字,原样发送,如果是空格,转换为+,如果是中文/其他字符,则直接把字符串用BASE64加密。
Get
传输的数据有大小限制,因为GET是通过URL提交数据,那么GET可提交的数据量就跟URL的长度有直接关系了,不同的浏览器对URL的长度的限制是不同的。

Post请求则作为http消息的实际内容发送给web服务器,数据放置在HTML Header内提交,Post没有限制提交的数据。PostGet安全,当数据是中文或者不敏感的数据,则用get,因为使用get,参数会显示在地址,对于敏感数据和不是中文字符的数据,则用post

从底层说:

GET产生一个TCP数据包;POST产生两个TCP数据包。

对于GET方式的请求,浏览器会把http header和data一并发送出去,服务器响应200(返回数据);

而对于POST,浏览器先发送header,服务器响应100 continue,浏览器再发送data,服务器响应200 ok(返回数据)。

 

这里主要用到的是两种,微信登录用的是 get 请求方式,带上参数请求token,

而微信支付用的post 请求方式,将XML数据post给服务器。

 

4.具体demo:

微信登录:

 

1.      服务端通过客户端获取的code去向微信开发平台请求,获取token :

https://api.weixin.qq.com/sns/oauth2/access_token"++
                   "?appid="++?AppId++
                   "&secret="++?Secret++
                   "&code="++Code++
                   "&grant_type=authorization_code",
fun_http:async_http_request(get,{Url,[]},{?MODULE, getTokenCb, {}}).

 

2.      以上demo是url所带的参数,注意:url和传输数据之间要用?分割 ,请求方式是get,最后加上自己的异步回调函数,带着token 再去授权:

Url="https://api.weixin.qq.com/sns/auth"++
                   "?access_token="++Token++
                   "&openid="++OpenId,
fun_http:async_http_request(get,{Url,[]}, {?MODULE,authCb, {Token,OpenId}}).

 

3.      授权之后再去获取个人信息:

Url="https://api.weixin.qq.com/sns/userinfo"++
         "?access_token="++Token++
         "&openid="++OpenId,
fun_http:async_http_request(get,{Url,[]}, {?MODULE,getUserInfoCb, {}}).

至此微信登录就完成了。因为微信平台回复的都是json字符串,很好解析,就不详细说了。

  

下面重点说的是:微信支付

微信支付,从下单开始:

1.      服务端向微信请求预支付订单号,再发给前端。

 这里官方要的是XML数据,所以用post方式将XML数据发给微信的服务器。Erlang中封装xml的方式,最简单暴力的就是将XML数据封装成一个字符串,发过去就可以,实践证明可行的:

   

 getPrepayId(TradeId,Ip,Price)->     
         Str=get_randStr(),     %%生成随机串,自己实现
         StrA="appid="++?AppId++
                             "&body=APP"++
                             "&mch_id="++?Mch_id++
                             "&nonce_str="++Str++
                             "¬ify_url=www.baidu.com"++            
                             "&out_trade_no="++TradeId++
                             "&spbill_create_ip="++ip2str(Ip)++
                             "&total_fee="++util:to_list(Price*100)++
                             "&trade_type=APP",
         StrSignTemp=StrA++"&key=rtyuiophjklyhjkyhjkjkljk",       
         Sign=string:to_upper(util:md5(StrSignTemp)),
         Url="https://api.mch.weixin.qq.com/pay/unifiedorder",
         Data="<xml><appid>"++?AppId++"</appid>"++
                             "<body>APP</body>"++
                             "<mch_id>"++?Mch_id++"</mch_id>"++
                             "<nonce_str>"++Str++"</nonce_str>"++
                             "<notify_url> www.baidu.com </notify_url>"++
                             "<out_trade_no>"++TradeId++"</out_trade_no>"++
                             "<spbill_create_ip>"++ip2str(Ip)++"</spbill_create_ip>"++
                             "<total_fee>"++util:to_list(Price*100)++"</total_fee>"++
                             "<trade_type>APP</trade_type>"++
                             "<sign>"++Sign++"</sign>"++
                             "</xml>",                
 fun_http:async_http_request(post,{Url,[],"text/xml",Data},{?MODULE, getPrepayIdCb,{TradeId,Price}}).


如上demo 可以看到,先将需要发送的参数,拼一起成strA,再strA++"&key=rtyuiophjklyhjkyhjkjkljk"= StrSignTemp,再将这个字符串先MD5加密,再执行一次转换大写的操作,签名就生成了。这时候再将这些参数按照标签的形式<appid>"++?AppId++"</appid>" 拼一起,最后封装成一个XML数据的字符串data,再向官方的Url postdata.这时候请求就成功了。注意:Data中的每一个参数和上面生成签名的每一个同名参数得一致,签名不能错误,方式是post data.这些都正确就可以收到微信回复的XML数据,得到预支付订单号prepay_id。

 

2.      Erlang中xmerl的方法可以解析XML,但网上少有可以完成解析XML的demo.下面是自己解析的方法(究其原理,就是一层一层的将节点剥离出来,最后得到其中的一层的某个字段):


-record(xmlNamespace,{k1=[],k2=[]}).
-record(xmlElement,{
                                               name,               % atom()
                                               expanded_name= [],     % string() | {URI,Local} |{"xmlns",Local}
                                               nsinfo= [],             % {Prefix, Local} | []
                                               namespace=#xmlNamespace{},
                                               parents= [],          % [{atom(),integer()}]
                                               pos,               % integer()
                                               attributes= [],%[#xmlAttribute()],
                                               content= [],
                                               language= "",     % string()
                                               xmlbase="",           % string() XML Base path, forrelative URI:s
                                               elementdef=undeclared% atom(), one of [undeclared | prolog | external | element]
                                        }).
-record(xmlText,{parents=[],pos=0,attributes=[],value="",name}).
 
getPrepayIdCb({_StatusLine,Body},{TradeId,Price})->
         ?log("!!!!!!~p",[Body]),
         Str=util:to_list(Body),
         {XmlElt,_}=xmerl_scan:string(Str),
         Items= xmerl_xpath:string("/xml", XmlElt),
         Prepay_id= lists:foldl(fun(Item, T) ->
                   [#xmlElement{content=Content}]=xmerl_xpath:string("/xml/prepay_id", Item),
                               case Content of
                                       [#xmlText{value=Prepay_id1}]->Prepay_id1++T;
                                           _->T
                                     end  end,"",Items).


如上,需要定义三个record。字段可以自己命名,Body就是解析http请求回复的数据,然后先将binary文件转化成list, 再通过xmerl_scan:string(Str)方法,提取出XML的节点元素。再通过xmerl_xpath:string("/xml", XmlElt)方法,提取出XML节点下的所有数据。        再通过下面的[#xmlElement{content=Content}]=xmerl_xpath:string("/xml/prepay_id", Item)

方法,找到prepay_id 这个标签的节点数据,和#xmlElement 匹配,其中的content就是我们要的,而content去和xmlText 记录匹配,其中的value字段就是我们要的prepay_id的值。其他字段同理可以获得。

注意:只要理解了erlang的匹配原理,record对应的字段都是自己命名,自己可以任意取出来的。

如客户端支付成功后,服务端去验证是否成功,需要获取的字段trade_state的值是否为SUCCESS

         Flag= lists:foldl(fun(Item, T) ->
                                 [#xmlElement{content=Content}]=xmerl_xpath:string("/xml/trade_state", Item),
                                  case Content of
                                             [#xmlText{value=Va}]-> Va++T;
                                              _->T
                                  end   end,"", Items).

以上是个人做微信接口交互的时候的心得,只想分享一些成功的可以实用的方法,erlang开源东西太少,找到可用的方法太少。欢迎分享,指教,转载注出处,谢谢。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值