首頁 >微信小程式 >小程式開發 >微信小程式 付款簡單實例及注意事項

微信小程式 付款簡單實例及注意事項

高洛峰
高洛峰原創
2017-01-10 09:59:122457瀏覽

微信小程式支付

微信小程式的支付和微信公眾號的支付是類似的,對比起來還比公眾號支付簡單了一些,我們只需要調用微信的統一下單接口獲取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 = "<xml>"
  formData += "<appid>" + appid + "</appid>" //appid 
  formData += "<attach>" + attach + "</attach>" //附加数据 
  formData += "<body>" + body + "</body>"
  formData += "<mch_id>" + mch_id + "</mch_id>" //商户号 
  formData += "<nonce_str>" + nonce_str + "</nonce_str>" //随机字符串,不长于32位。 
  formData += "<notify_url>" + notify_url + "</notify_url>"
  formData += "<openid>" + openid + "</openid>"
  formData += "<out_trade_no>" + bookingNo + "</out_trade_no>"
  formData += "<spbill_create_ip>61.50.221.43</spbill_create_ip>"
  formData += "<total_fee>" + total_fee + "</total_fee>"
  formData += "<trade_type>JSAPI</trade_type>"
  formData += "<sign>" + this.paysignjsapi(appid, attach, body, mch_id, nonce_str, notify_url, openid, bookingNo, &#39;61.50.221.43&#39;, total_fee, &#39;JSAPI&#39;) + "</sign>"
  formData += "</xml>"
  var self = this
  request({ 
   url: url, 
   method: &#39;POST&#39;, 
   body: formData 
  }, function(err, response, body) { 
   if (!err && response.statusCode == 200) { 
    var prepay_id = self.getXMLNodeValue(&#39;prepay_id&#39;, body.toString("utf-8")) 
    var tmp = prepay_id.split(&#39;[&#39;) 
    var tmp1 = tmp[2].split(&#39;]&#39;) 
    //签名 
    var _paySignjs = self.paysignjs(appid, nonce_str, &#39;prepay_id=&#39; + tmp1[0], &#39;MD5&#39;, 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 + &#39;&key=&#39; + key 
  var crypto = require(&#39;crypto&#39;) 
  var sign = crypto.createHash(&#39;md5&#39;).update(string, &#39;utf8&#39;).digest(&#39;hex&#39;) 
  return sign.toUpperCase()

支付sign:

var ret = {
    appId: appid,
    nonceStr: nonceStr,
    package: package,
    signType: signType,
    timeStamp: timeStamp
  }
  var string = this.raw(ret)
  string = string + &#39;&key=&#39; + key
  var sign = crypto.createHash(&#39;md5&#39;).update(string, &#39;utf8&#39;).digest(&#39;hex&#39;)
  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 = &#39;&#39;
  for (var k in newArgs) {
    string += &#39;&&#39; + k + &#39;=&#39; + newArgs[k]
  }
  string = string.substr(1)
  return string

統一下單一介面回傳的是帶有prepay_id的xml,所以我們需要一個方法來解析,程式碼如下:

var tmp = xml.split("<" + node_name + ">")
  var _tmp = tmp[1].split("</" + node_name + ">")
  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("</" + node_name + ">")
  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 = &#39;&#39;
  for (var k in newArgs) {
    string += &#39;&&#39; + k + &#39;=&#39; + 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 + &#39;&key=&#39; + key
  var sign = crypto.createHash(&#39;md5&#39;).update(string, &#39;utf8&#39;).digest(&#39;hex&#39;)
  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
 }
}

   

之後我們只需要單在介面程式裡面呼叫這個接口,就會獲取到所有的支付需要信息,再掉微信支付即可。

這裡說幾個小程序支付的坑:

1.統一下單接口是xml(這個不只是小程序,公眾號也是),返回值也是xml格式需要自己獲取prepay_id,

2.簽名算法要帶上key,最後要轉換成大些

3.微信支付的sign算法也要帶上appid(這個不科學,深坑)

4.簽名算法一定不要用json拼接key

感謝閱讀,希望能幫助大家,謝謝大家對本站的支持!

更多微信小程式 付款簡單實例及注意事項相關文章請關注PHP中文網!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn