找回密码
 立即注册

QQ登录

只需一步,快速开始

微信小程序开发资源

关注:1395

所属分类: 微信开发 微信小程序开发资源

本版块为微信小程序资源分享版块,包括微信小程序开发中可能会用到的各类小程序开发工具、小程序demo及开发教程等。

快捷导航www.henkuai.com):微信小程序开发者社区微信小程序开发问答微信小程序开发交流群

[最新文章] 微信小程序 支付简单实例及注意事项

[复制链接]
查看: 2194|回复: 14
最佳答案
0 

3

主题

3

帖子

60

积分

新人求带

积分
60
 楼主| 发表于 2017-2-17 18:04:45 | 显示全部楼层 |阅读模式
微信小程序支付

微信小程序的支付和微信公众号的支付是类似的,对比起来还比公众号支付简单了一些,我们只需要调用微信的统一下单接口获取prepay_id之后我们在调用微信的支付即可。
今天我们来封装一般node的支付接口!!!

首先调用统一下单接口我们需要知道一些信息
  1. var bookingNo = 'davdian' + this.createNonceStr() + this.createTimeStamp()
  2.   var deferred = Q.defer()
  3.   var appid = config.appId
  4.   var nonce_str = this.createNonceStr()
  5.   var timeStamp = this.createTimeStamp()
  6.   var url = "https://api.mch.weixin.qq.com/pay/unifiedorder"
  7.   var formData = "<xml>"
  8.   formData += "<appid>" + appid + "</appid>" //appid
  9.   formData += "<attach>" + attach + "</attach>" //附加数据
  10.   formData += "<body>" + body + "</body>"
  11.   formData += "<mch_id>" + mch_id + "</mch_id>" //商户号
  12.   formData += "<nonce_str>" + nonce_str + "</nonce_str>" //随机字符串,不长于32位。
  13.   formData += "<notify_url>" + notify_url + "</notify_url>"
  14.   formData += "<openid>" + openid + "</openid>"
  15.   formData += "<out_trade_no>" + bookingNo + "</out_trade_no>"
  16.   formData += "<spbill_create_ip>61.50.221.43</spbill_create_ip>"
  17.   formData += "<total_fee>" + total_fee + "</total_fee>"
  18.   formData += "<trade_type>JSAPI</trade_type>"
  19.   formData += "<sign>" + this.paysignjsapi(appid, attach, body, mch_id, nonce_str, notify_url, openid, bookingNo, '61.50.221.43', total_fee, 'JSAPI') + "</sign>"
  20.   formData += "</xml>"
  21.   var self = this
  22.   request({
  23.    url: url,
  24.    method: 'POST',
  25.    body: formData
  26.   }, function(err, response, body) {
  27.    if (!err && response.statusCode == 200) {
  28.     var prepay_id = self.getXMLNodeValue('prepay_id', body.toString("utf-8"))
  29.     var tmp = prepay_id.split('[')
  30.     var tmp1 = tmp[2].split(']')
  31.     //签名
  32.     var _paySignjs = self.paysignjs(appid, nonce_str, 'prepay_id=' + tmp1[0], 'MD5', timeStamp)
  33.     var args = {
  34.      appId: appid,
  35.      timeStamp: timeStamp,
  36.      nonceStr: nonce_str,
  37.      signType: "MD5",
  38.      package: tmp1[0],
  39.      paySign: _paySignjs
  40.     }
  41.     deferred.resolve(args)
  42.    } else {
  43.     console.log(body)
  44.    }
  45.   })
  46.   return deferred.promise
复制代码

这个是一个统一下单接口的代码,我们需要appid小程序公众号id,mch_id商户号id,openid小程序的唯一标实,key支付用的密码,剩下的参数都是订单的信息和价格之类的,本人require进q模块使用promise,这个因人而异,可以根据自己需要来。我们需要请求https://api.mch.weixin.qq.com/pay/unifiedorder接口

注意:这里我们传递的formdata是一个xml而不是json

然后我们需要签名方法,这里我们需要封装两个方法,一个是签名方法调用统一下单接口会用到,另一个是调用小程序支付用到

统一下单接口sign:
  1. var ret = {
  2.    appid: appid,
  3.    attach: attach,
  4.    body: body,
  5.    mch_id: mch_id,
  6.    nonce_str: nonce_str,
  7.    notify_url: notify_url,
  8.    openid: openid,
  9.    out_trade_no: out_trade_no,
  10.    spbill_create_ip: spbill_create_ip,
  11.    total_fee: total_fee,
  12.    trade_type: trade_type
  13.   }
  14.   var string = this.raw(ret)
  15.   string = string + '&key=' + key
  16.   var crypto = require('crypto')
  17.   var sign = crypto.createHash('md5').update(string, 'utf8').digest('hex')
  18.   return sign.toUpperCase()
复制代码

支付sign:
  1. var ret = {
  2.     appId: appid,
  3.     nonceStr: nonceStr,
  4.     package: package,
  5.     signType: signType,
  6.     timeStamp: timeStamp
  7.   }
  8.   var string = this.raw(ret)
  9.   string = string + '&key=' + key
  10.   var sign = crypto.createHash('md5').update(string, 'utf8').digest('hex')
  11.   return sign.toUpperCase()
复制代码

注意加密的时候我们获取的是string而不是一个json,所以我们需要吧json转换成string,代码如下:
  1. var keys = Object.keys(args)
  2.   keys = keys.sort()
  3.   var newArgs = {}
  4.   keys.forEach(function(key) {
  5.     newArgs[key] = args[key]
  6.   })
  7.   var string = ''
  8.   for (var k in newArgs) {
  9.     string += '&' + k + '=' + newArgs[k]
  10.   }
  11.   string = string.substr(1)
  12.   return string
复制代码

统一下单接口返回的是带有prepay_id的xml,所以我们需要一个方法进行解析,代码如下:
  1. var tmp = xml.split("<" + node_name + ">")
  2.   var _tmp = tmp[1].split("</" + node_name + ">")
  3.   return _tmp[0]
复制代码

最后我们只需要把这些连接到一起就是可以获取所有微信支付所需参数,代码如下:
  1. //微信小程序支付封装,暂支持md5加密,不支持sha1
  2. /**
  3. ***create order by jianchep 2016/11/22   
  4. **/
  5. var config = require('../config/weapp.js')
  6. var Q = require("q")
  7. var request = require("request")
  8. var crypto = require('crypto')
  9. var ejs = require('ejs')
  10. var fs = require('fs')
  11. var key = config.key
  12. module.exports = {
  13. // 获取prepay_id
  14. getXMLNodeValue: function(node_name, xml) {
  15.   var tmp = xml.split("<" + node_name + ">")
  16.   var _tmp = tmp[1].split("</" + node_name + ">")
  17.   return _tmp[0]
  18. },
  19. // object-->string
  20. raw: function(args) {
  21.   var keys = Object.keys(args)
  22.   keys = keys.sort()
  23.   var newArgs = {}
  24.   keys.forEach(function(key) {
  25.     newArgs[key] = args[key]
  26.   })
  27.   var string = ''
  28.   for (var k in newArgs) {
  29.     string += '&' + k + '=' + newArgs[k]
  30.   }
  31.   string = string.substr(1)
  32.   return string
  33. },
  34.   // 随机字符串产生函数
  35. createNonceStr: function() {
  36.    return Math.random().toString(36).substr(2, 15)
  37. },
  38. // 时间戳产生函数
  39. createTimeStamp: function() {
  40.    return parseInt(new Date().getTime() / 1000) + ''
  41. },
  42. // 支付md5加密获取sign
  43. paysignjs: function(appid, nonceStr, package, signType, timeStamp) {
  44.   var ret = {
  45.     appId: appid,
  46.     nonceStr: nonceStr,
  47.     package: package,
  48.     signType: signType,
  49.     timeStamp: timeStamp
  50.   }
  51.   var string = this.raw(ret)
  52.   string = string + '&key=' + key
  53.   var sign = crypto.createHash('md5').update(string, 'utf8').digest('hex')
  54.   return sign.toUpperCase()
  55. },
  56. // 统一下单接口加密获取sign
  57. paysignjsapi: function(appid, attach, body, mch_id, nonce_str, notify_url, openid, out_trade_no, spbill_create_ip, total_fee, trade_type) {
  58.   var ret = {
  59.    appid: appid,
  60.    attach: attach,
  61.    body: body,
  62.    mch_id: mch_id,
  63.    nonce_str: nonce_str,
  64.    notify_url: notify_url,
  65.    openid: openid,
  66.    out_trade_no: out_trade_no,
  67.    spbill_create_ip: spbill_create_ip,
  68.    total_fee: total_fee,
  69.    trade_type: trade_type
  70.   }
  71.   var string = this.raw(ret)
  72.   string = string + '&key=' + key
  73.   var crypto = require('crypto')
  74.   var sign = crypto.createHash('md5').update(string, 'utf8').digest('hex')
  75.   return sign.toUpperCase()
  76. },
  77. // 下单接口
  78. order: function(attach, body, mch_id, openid, total_fee, notify_url) {
  79.   var bookingNo = 'davdian' + this.createNonceStr() + this.createTimeStamp()
  80.   var deferred = Q.defer()
  81.   var appid = config.appId
  82.   var nonce_str = this.createNonceStr()
  83.   var timeStamp = this.createTimeStamp()
  84.   var url = "https://api.mch.weixin.qq.com/pay/unifiedorder"
  85.   var formData = "<xml>"
  86.   formData += "<appid>" + appid + "</appid>" //appid
  87.   formData += "<attach>" + attach + "</attach>" //附加数据
  88.   formData += "<body>" + body + "</body>"
  89.   formData += "<mch_id>" + mch_id + "</mch_id>" //商户号
  90.   formData += "<nonce_str>" + nonce_str + "</nonce_str>" //随机字符串,不长于32位。
  91.   formData += "<notify_url>" + notify_url + "</notify_url>"
  92.   formData += "<openid>" + openid + "</openid>"
  93.   formData += "<out_trade_no>" + bookingNo + "</out_trade_no>"
  94.   formData += "<spbill_create_ip>61.50.221.43</spbill_create_ip>"
  95.   formData += "<total_fee>" + total_fee + "</total_fee>"
  96.   formData += "<trade_type>JSAPI</trade_type>"
  97.   formData += "<sign>" + this.paysignjsapi(appid, attach, body, mch_id, nonce_str, notify_url, openid, bookingNo, '61.50.221.43', total_fee, 'JSAPI') + "</sign>"
  98.   formData += "</xml>"
  99.   var self = this
  100.   request({
  101.    url: url,
  102.    method: 'POST',
  103.    body: formData
  104.   }, function(err, response, body) {
  105.    if (!err && response.statusCode == 200) {
  106.     var prepay_id = self.getXMLNodeValue('prepay_id', body.toString("utf-8"))
  107.     var tmp = prepay_id.split('[')
  108.     var tmp1 = tmp[2].split(']')
  109.     //签名
  110.     var _paySignjs = self.paysignjs(appid, nonce_str, 'prepay_id=' + tmp1[0], 'MD5', timeStamp)
  111.     var args = {
  112.      appId: appid,
  113.      timeStamp: timeStamp,
  114.      nonceStr: nonce_str,
  115.      signType: "MD5",
  116.      package: tmp1[0],
  117.      paySign: _paySignjs
  118.     }
  119.     deferred.resolve(args)
  120.    } else {
  121.     console.log(body)
  122.    }
  123.   })
  124.   return deferred.promise
  125. }
  126. }
复制代码

之后我们封装下单接口:
  1. unifiedorder: function (req, res) {
  2.   var body = "测试支付"
  3.   var openid = "openid"
  4.   var total_fee = 1
  5.   var notify_url = "http://localhost/notify"
  6.   var mch_id = config.shopId
  7.   var attach = "测试"
  8.   wxpay.order(attach, body, mch_id, openid, total_fee, notify_url)
  9.    .then(function(data){
  10.     console.log('data--->', data, 123123)
  11.     res.json(data)
  12.    })
  13. },
复制代码

然后我们只需要在小程序里面调用这个接口,就会获取到所有的支付需要信息,再掉微信支付即可。

这里说几个小程序支付的坑:
1.统一下单接口是xml(这个不只是小程序,公众号也是),返回值也是xml格式需要自己获取prepay_id,
2.签名算法要带上key,最后要转换成大些
3.微信支付的sign算法也要带上appid(这个不科学,深坑)
4.签名算法一定不要用json拼接key
回复

使用道具 举报

最佳答案
0 

0

主题

3

帖子

181

积分

新人求带

积分
181
发表于 2017-2-21 11:19:31 | 显示全部楼层
学习了
回复

使用道具 举报

最佳答案
0 

0

主题

5

帖子

205

积分

新人求带

积分
205
发表于 2017-3-8 16:30:10 | 显示全部楼层
感谢分享。可是在算统一支付下单sign时,
用var sign=crypto.createHash('md5').update(string),'utf-8').digest('hex').toUpperCase()
算出的结果和微信加密校验接口算出来的不一样。你自己用过没问题吗?
回复 支持 反对

使用道具 举报

最佳答案
0 

3

主题

6

帖子

159

积分

新人求带

积分
159
发表于 2017-3-8 16:43:57 | 显示全部楼层
闻风识香 发表于 2017-3-8 16:30
感谢分享。可是在算统一支付下单sign时,
用var sign=crypto.createHash('md5').update(string),'utf-8').d ...

自己检查一遍各种参数包括大小写、支付目录、AppSecret等等
回复 支持 反对

使用道具 举报

最佳答案
0 

0

主题

6

帖子

353

积分

略知一二

积分
353
发表于 2017-3-12 23:10:41 | 显示全部楼层
客服壹号服务不错 赞一个!!!
回复 支持 反对

使用道具 举报

最佳答案
0 

0

主题

8

帖子

68

积分

新人求带

积分
68
发表于 2017-3-13 14:25:10 | 显示全部楼层
这里的东西好贵啊
回复 支持 反对

使用道具 举报

最佳答案
0 

0

主题

5

帖子

49

积分

新人求带

积分
49
发表于 2017-3-20 16:42:15 | 显示全部楼层
感谢分享 学习了
回复 支持 反对

使用道具 举报

最佳答案
0 

0

主题

12

帖子

194

积分

新人求带

积分
194
发表于 2017-3-29 22:03:07 | 显示全部楼层
看不懂啊,哎都是泪。
回复 支持 反对

使用道具 举报

最佳答案
0 

0

主题

10

帖子

39

积分

新人求带

积分
39
发表于 2017-4-10 17:45:11 | 显示全部楼层
6666666666666666666
回复 支持 反对

使用道具 举报

最佳答案
0 

0

主题

9

帖子

118

积分

新人求带

积分
118
发表于 2017-5-6 17:43:40 | 显示全部楼层
学习楼主
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关闭

站长推荐 上一条 /1 下一条


易域网-您身边的域名管家

henkuai.com是专业的第三方微信开发者平台,为生态而生。


本站为第三方微信开发者平台,非腾讯官方网站。

天津市滨海新区
中新生态城中成大道生态建设公寓9号楼3层301

欢迎来这里一起喝喝茶,
聊聊你的产品。

微信公众号gongzhongkaifa

工作日12小时内回复。

网站业务
zhongcong@henkuai.com

工作日12小时内回复。

市场合作
songchang@henkuai.com