微信小程序的支付和微信公众号的支付是类似的,对比起来还比公众号支付简单了一些,我们只需要调用微信的统一下单接口获取 prepay_id 之后我们在调用微信的支付即可。
今天我们来封装一般 node 的支付接口!!!
首先调用统一下单接口我们需要知道一些信息
- var bookingNo = 'davdian' + this.createNonceStr() + this.createTimeStamp()
- var deferred = Q.defer()
- var appid = config.appId
- var nonce_str = this.createNonceStr()
- var timeStamp = this.createTimeStamp()
- var url = "https://api.mch.weixin.qq.com/pay/unifiedorder"
- var formData = ""
- formData += "" + appid + "" //appid
- formData += "" + attach + "" //附加数据
- formData += "" + body + ""
- formData += "" + mch_id + "" //商户号
- formData += "" + nonce_str + "" //随机字符串,不长于32位。
- formData += "" + notify_url + ""
- formData += "" + openid + ""
- formData += "" + bookingNo + ""
- formData += "61.50.221.43"
- formData += "" + total_fee + ""
- formData += "JSAPI"
- formData += "" + this.paysignjsapi(appid, attach, body, mch_id, nonce_str, notify_url, openid, bookingNo, '61.50.221.43', total_fee, 'JSAPI') + ""
- formData += ""
- var self = this
- request({
- url: url,
- method: 'POST',
- body: formData
- }, function(err, response, body) {
- if (!err && response.statusCode == 200) {
- var prepay_id = self.getXMLNodeValue('prepay_id', body.toString("utf-8"))
- var tmp = prepay_id.split('[')
- var tmp1 = tmp[2].split(']')
- //签名
- var _paySignjs = self.paysignjs(appid, nonce_str, 'prepay_id=' + tmp1[0], 'MD5', timeStamp)
- var args = {
- appId: appid,
- timeStamp: timeStamp,
- nonceStr: nonce_str,
- signType: "MD5",
- package: tmp1[0],
- paySign: _paySignjs
- }
- deferred.resolve(args)
- } else {
- console.log(body)
- }
- })
- 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:
- var ret = {
- appid: appid,
- attach: attach,
- body: body,
- mch_id: mch_id,
- nonce_str: nonce_str,
- notify_url: notify_url,
- openid: openid,
- out_trade_no: out_trade_no,
- spbill_create_ip: spbill_create_ip,
- total_fee: total_fee,
- trade_type: trade_type
- }
- var string = this.raw(ret)
- string = string + '&key=' + key
- var crypto = require('crypto')
- var sign = crypto.createHash('md5').update(string, 'utf8').digest('hex')
- return sign.toUpperCase()
- 支付sign:
- var ret = {
- appId: appid,
- nonceStr: nonceStr,
- package: package,
- signType: signType,
- timeStamp: timeStamp
- }
- var string = this.raw(ret)
- string = string + '&key=' + key
- var sign = crypto.createHash('md5').update(string, 'utf8').digest('hex')
- return sign.toUpperCase()
- 注意加密的时候我们获取的是string而不是一个json,所以我们需要吧json转换成string,代码如下:
- var keys = Object.keys(args)
- keys = keys.sort()
- var newArgs = {}
- keys.forEach(function(key) {
- newArgs[key] = args[key]
- })
- var string = ''
- for (var k in newArgs) {
- string += '&' + k + '=' + newArgs[k]
- }
- string = string.substr(1)
- return string
- 统一下单接口返回的是带有prepay_id的xml,所以我们需要一个方法进行解析,代码如下:
- var tmp = xml.split("<" + node_name + ">")
- var _tmp = tmp[1].split("")
- return _tmp[0]
- 最后我们只需要把这些连接到一起就是可以获取所有微信支付所需参数,代码如下:
- //微信小程序支付封装,暂支持md5加密,不支持sha1
- /**
- ***create order by jianchep 2016/11/22
- **/
- var config = require('../config/weapp.js')
- var Q = require("q")
- var request = require("request")
- var crypto = require('crypto')
- var ejs = require('ejs')
- var fs = require('fs')
- var key = config.key
- module.exports = {
- // 获取prepay_id
- getXMLNodeValue: function(node_name, xml) {
- var tmp = xml.split("<" + node_name + ">")
- var _tmp = tmp[1].split("")
- return _tmp[0]
- },
- // object-->string
- raw: function(args) {
- var keys = Object.keys(args)
- keys = keys.sort()
- var newArgs = {}
- keys.forEach(function(key) {
- newArgs[key] = args[key]
- })
- var string = ''
- for (var k in newArgs) {
- string += '&' + k + '=' + newArgs[k]
- }
- string = string.substr(1)
- return string
- },
- // 随机字符串产生函数
- createNonceStr: function() {
- return Math.random().toString(36).substr(2, 15)
- },
- // 时间戳产生函数
- createTimeStamp: function() {
- return parseInt(new Date().getTime() / 1000) + ''
- },
- // 支付md5加密获取sign
- paysignjs: function(appid, nonceStr, package, signType, timeStamp) {
- var ret = {
- appId: appid,
- nonceStr: nonceStr,
- package: package,
- signType: signType,
- timeStamp: timeStamp
- }
- var string = this.raw(ret)
- string = string + '&key=' + key
- var sign = crypto.createHash('md5').update(string, 'utf8').digest('hex')
- return sign.toUpperCase()
- },
- // 统一下单接口加密获取sign
- paysignjsapi: function(appid, attach, body, mch_id, nonce_str, notify_url, openid, out_trade_no, spbill_create_ip, total_fee, trade_type) {
- var ret = {
- appid: appid,
- attach: attach,
- body: body,
- mch_id: mch_id,
- nonce_str: nonce_str,
- notify_url: notify_url,
- openid: openid,
- out_trade_no: out_trade_no,
- spbill_create_ip: spbill_create_ip,
- total_fee: total_fee,
- trade_type: trade_type
- }
- var string = this.raw(ret)
- string = string + '&key=' + key
- var crypto = require('crypto')
- var sign = crypto.createHash('md5').update(string, 'utf8').digest('hex')
- return sign.toUpperCase()
- },
- // 下单接口
- order: function(attach, body, mch_id, openid, total_fee, notify_url) {
- var bookingNo = 'davdian' + this.createNonceStr() + this.createTimeStamp()
- var deferred = Q.defer()
- var appid = config.appId
- var nonce_str = this.createNonceStr()
- var timeStamp = this.createTimeStamp()
- var url = "https://api.mch.weixin.qq.com/pay/unifiedorder"
- var formData = ""
- formData += "" + appid + "" //appid
- formData += "" + attach + "" //附加数据
- formData += "" + body + ""
- formData += "" + mch_id + "" //商户号
- formData += "" + nonce_str + "" //随机字符串,不长于32位。
- formData += "" + notify_url + ""
- formData += "" + openid + ""
- formData += "" + bookingNo + ""
- formData += "61.50.221.43"
- formData += "" + total_fee + ""
- formData += "JSAPI"
- formData += "" + this.paysignjsapi(appid, attach, body, mch_id, nonce_str, notify_url, openid, bookingNo, '61.50.221.43', total_fee, 'JSAPI') + ""
- formData += ""
- var self = this
- request({
- url: url,
- method: 'POST',
- body: formData
- }, function(err, response, body) {
- if (!err && response.statusCode == 200) {
- var prepay_id = self.getXMLNodeValue('prepay_id', body.toString("utf-8"))
- var tmp = prepay_id.split('[')
- var tmp1 = tmp[2].split(']')
- //签名
- var _paySignjs = self.paysignjs(appid, nonce_str, 'prepay_id=' + tmp1[0], 'MD5', timeStamp)
- var args = {
- appId: appid,
- timeStamp: timeStamp,
- nonceStr: nonce_str,
- signType: "MD5",
- package: tmp1[0],
- paySign: _paySignjs
- }
- deferred.resolve(args)
- } else {
- console.log(body)
- }
- })
- return deferred.promise
- }
- }
- 之后我们封装下单接口:
- unifiedorder: function (req, res) {
- var body = "测试支付"
- var openid = "openid"
- var total_fee = 1
- var notify_url = "http://localhost/notify"
- var mch_id = config.shopId
- var attach = "测试"
- wxpay.order(attach, body, mch_id, openid, total_fee, notify_url)
- .then(function(data){
- console.log('data--->', data, 123123)
- res.json(data)
- })
- },
然后我们只需要在小程序里面调用这个接口,就会获取到所有的支付需要信息,再掉微信支付即可。
这里说几个小程序支付的坑:
1. 统一下单接口是 xml(这个不只是小程序,公众号也是),返回值也是 xml 格式需要自己获取 prepay_id,
2. 签名算法要带上 key,最后要转换成大些
3. 微信支付的 sign 算法也要带上 appid(这个不科学,深坑)
4. 签名算法一定不要用 json 拼接 key
来源: http://www.bubuko.com/infodetail-2000275.html