博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Erlang服务端与微信登录和微信支付接口的交互
阅读量:2058 次
发布时间:2019-04-29

本文共 4895 字,大约阅读时间需要 16 分钟。

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

1.  先看看微信开放平台的官方开发文档:

 如图:

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

 

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

微信登录API的文档链接:

 

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 :

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

 

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

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

 

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

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

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

  

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

微信支付,从下单开始:

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

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

   

 
  1. getPrepayId(TradeId,Ip,Price)->
  2. Str=get_randStr(), %%生成随机串,自己实现
  3. StrA=
    "appid="++?AppId++
  4. "&body=APP"++
  5. "&mch_id="++?Mch_id++
  6. "&nonce_str="++Str++
  7. "¬ify_url=www.baidu.com"++
  8. "&out_trade_no="++TradeId++
  9. "&spbill_create_ip="++ip2str(Ip)++
  10. "&total_fee="++util:to_list(Price*
    100)++
  11. "&trade_type=APP",
  12. StrSignTemp=StrA++
    "&key=rtyuiophjklyhjkyhjkjkljk",
  13. Sign=
    string:to_upper(util:md5(StrSignTemp)),
  14. Url=
    "https://api.mch.weixin.qq.com/pay/unifiedorder",
  15. Data=
    "<xml><appid>"++?AppId++
    "</appid>"++
  16. "<body>APP</body>"++
  17. "<mch_id>"++?Mch_id++
    "</mch_id>"++
  18. "<nonce_str>"++Str++
    "</nonce_str>"++
  19. "<notify_url> www.baidu.com </notify_url>"++
  20. "<out_trade_no>"++TradeId++
    "</out_trade_no>"++
  21. "<spbill_create_ip>"++ip2str(Ip)++
    "</spbill_create_ip>"++
  22. "<total_fee>"++util:to_list(Price*
    100)++
    "</total_fee>"++
  23. "<trade_type>APP</trade_type>"++
  24. "<sign>"++Sign++
    "</sign>"++
  25. "</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.下面是自己解析的方法(究其原理,就是一层一层的将节点剥离出来,最后得到其中的一层的某个字段):

 
  1. -record(xmlNamespace,{k1=[],k2=[]}).
  2. -record(xmlElement,{
  3. name, % atom()
  4. expanded_name= [], %
    string() | {URI,Local} |{
    "xmlns",Local}
  5. nsinfo= [], % {Prefix, Local} | []
  6. namespace=#xmlNamespace{},
  7. parents= [], % [{atom(),integer()}]
  8. pos, % integer()
  9. attributes= [],%[#xmlAttribute()],
  10. content= [],
  11. language=
    "", %
    string()
  12. xmlbase=
    "", %
    string() XML Base path, forrelative URI:s
  13. elementdef=undeclared% atom(), one of [undeclared | prolog | external | element]
  14. }).
  15. -record(xmlText,{parents=[],pos=
    0,attributes=[],value=
    "",name}).
  16. getPrepayIdCb({_StatusLine,Body},{TradeId,Price})->
  17. ?
    log(
    "!!!!!!~p",[Body]),
  18. Str=util:to_list(Body),
  19. {XmlElt,_}=xmerl_scan:
    string(Str),
  20. Items= xmerl_xpath:
    string(
    "/xml", XmlElt),
  21. Prepay_id= lists:foldl(fun(Item, T) ->
  22. [#xmlElement{content=Content}]=xmerl_xpath:
    string(
    "/xml/prepay_id", Item),
  23. case Content of
  24. [#xmlText{value=Prepay_id1}]->Prepay_id1++T;
  25. _->T
  26. 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

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

转自:Zmyths 链接地址 https://blog.csdn.net/zcyzsy/article/details/70256149

你可能感兴趣的文章
linux系统 阿里云源
查看>>
国内外helm源记录
查看>>
牛客网题目1:最大数
查看>>
散落人间知识点记录one
查看>>
Leetcode C++ 随手刷 547.朋友圈
查看>>
手抄笔记:深入理解linux内核-1
查看>>
内存堆与栈
查看>>
Leetcode C++《每日一题》20200621 124.二叉树的最大路径和
查看>>
Leetcode C++《每日一题》20200622 面试题 16.18. 模式匹配
查看>>
Leetcode C++《每日一题》20200625 139. 单词拆分
查看>>
Leetcode C++《每日一题》20200626 338. 比特位计数
查看>>
Leetcode C++ 《拓扑排序-1》20200626 207.课程表
查看>>
Go语言学习Part1:包、变量和函数
查看>>
Go语言学习Part2:流程控制语句:for、if、else、switch 和 defer
查看>>
Go语言学习Part3:struct、slice和映射
查看>>
Go语言学习Part4-1:方法和接口
查看>>
Leetcode Go 《精选TOP面试题》20200628 69.x的平方根
查看>>
Leetcode C++ 剑指 Offer 09. 用两个栈实现队列
查看>>
Leetcode C++《每日一题》20200707 112. 路径总和
查看>>
云原生 第十一章 应用健康
查看>>