微信小程序微信支付官方流程圖連接 javascript
主要代碼:php
//第一步,本地發起下單請求並傳送數據。這一步,在你的wxml中的某個元素
//中綁定事件<button bindtap='pay'></button>。經過這個pay函數,
//觸發雲函數並傳遞一些數據
pay: function(){
//須要上傳給雲函數的數據
let uploadData = {
//這次須要支付的金額,單位是分。例如¥1.80=180
"total_fee": "180",
//用戶端的ip地址
"spbill_create_ip": "123.123.123.123"
}
//調用雲函數
wx.cloud.callFunction({
//雲函數的名字,這裏我定義爲payment
name: "payment",
//須要上傳的數據
data: uploadData
}).then(res => {
//這個res就是雲函數返回的5個參數
//經過wx.requestPayment發起支付
wx.requestPayment({
timeStamp: res.result.data.timeStamp,
nonceStr: res.result.data.nonceStr,
package: res.result.data.package,
signType: res.result.data.signType,
paySign: res.result.data.paySign,
success: res => {
//支付成功
},
fail: err => {
//支付失敗
}
})
}
複製代碼
我建立的雲函數命名爲payment,此時雲函數結構應該爲java
payment
|__index.js
|__package.json
複製代碼
##每一步的詳細作法npm
這一步目的是獲取用戶的Openidjson
在雲函數的index.js中加上如下代碼小程序
//獲取雲實例
const cloud = require('wx-server-sdk')
//雲初始化
cloud.init()
//獲取微信調用上下文信息,其中包括Openid,Appid等
const wxContext = cloud.getWXContext()
//獲取用戶openid
const openid = wxContext.OPENID
複製代碼
微信支付開發文檔-統一下單微信小程序
這一步的目的是爲了生成調用支付統一下單API的訂單。根據官方文檔,咱們須要如下數據:api
appid(小程序ID)安全
openid(用戶OPENID)bash
mch_id(商戶號)
nonce_str(隨機字符串)
body(商品描述)
out_trade_no(商戶訂單號)
total_fee(標價金額)
spbill_create_ip(終端IP)
notify_url(通知地址)
trade_type(交易類型)
key(密鑰)
sign(簽名)
咱們一個一個解決。
小程序管理員進入公衆平臺、使用小程序賬戶登陸後,點擊左側菜單中的「設置」,在「開發設置」一項,就能夠查詢到小程序的AppID。
示例值
wxd678efh567hg6787
在雲函數的index.js中加上如下代碼:
const appid='wxwxd678efh567hg6787'
複製代碼
第一步已經得到。
示例值
oUpF8uMuAJO_M2pxb1Q9zNjWeS6o
登錄微信支付商戶平臺pay.weixin.qq.com,點擊上方「帳戶中心」,在「我的信息」中的「登錄帳號」就是mch_id。
示例值
1230000109
在雲函數的index.js中加上如下代碼:
const mch_id='1230000109'
複製代碼
任意生成的隨機數,不超過32位。你能夠本身寫個函數。
示例值
5K8264ILTKCH16CQ2502SI8ZNMTM67VS
我在雲函數中建立了一個新的JS文件(random.js)來保存這個函數,此時雲函數的結構以下
payment
|__index.js
|__package.json
|__random.js
複製代碼
其中random.js的內容爲:
function random(){
var result = ''
const wordList = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '1', '2',
'3', '4', '5', '6', '7', '8', '9', '0']
for(let i=0;i<31;i++){
result += wordList[Math.round(Math.random()*36)]
}
return result
}
module.exports = random()
複製代碼
而後在雲函數index.js中加上如下代碼:
const random = require("random.js")
複製代碼
格式爲:商家名稱-銷售商品類目
示例值
騰訊-遊戲
在雲函數index.js中加上如下代碼:
const body = "騰訊-遊戲"
複製代碼
商戶系統內部訂單號,要求32個字符內,只能是數字、大小寫字母_-|*且在同一個商戶號下惟一。由本身定義,推薦用當下時間+商品編號組成。
示例值
20150806125346
在雲函數index.js中的exports.main函數中加上如下代碼:
//這裏我只使用了當下時間。只要這個數字不是重複的就能夠。
const out_trade_no = Date.parse(new Date()).toString()
複製代碼
訂單總金額,單位爲分。好比當前需支付¥6.80,則total_fee爲680。
示例值
88
這裏須要用到咱們上傳過來的值,先無論
支持IPV4和IPV6兩種格式的IP地址。調用微信支付API的機器IP。
示例值
123.12.12.123
這裏須要用到咱們上傳過來的值,先無論
異步接收微信支付結果通知的回調地址,通知url必須爲外網可訪問的url,不能攜帶參數。在這裏能夠填上你本身服務器的url。
示例值
http://www.weixin.qq.com/wxpay/pay.php
在雲函數index.js中加上如下代碼:
//隨便填寫個服務器就行,我在使用中沒有遇到什麼問題
const notify_url = 'http://www.weixin.qq.com/wxpay/pay.php'
複製代碼
小程序的trade_type爲JSAPI。
示例值
JSAPI
在雲函數index.js中加上如下代碼:
const trade_type = 'JSAPI'
複製代碼
key爲商戶平臺設置的密鑰key,是由你本身設置的。key設置路徑:微信商戶平臺(pay.weixin.qq.com)-->帳戶設置-->API安全-->密鑰設置。
示例值
1a79a4d60de6718e8e5b326e338ae533
在雲函數index.js中加上如下代碼:
const key = '1a79a4d60de6718e8e5b326e338ae533'
複製代碼
將以上除key外全部信息按照參數名ASCII碼從大到小拼接成字符串,用&分割,將key放在最後。
字符串示例值:
appid=wxd678efh567hg6787&body=微信-遊戲&mch_
id=1230000109&nonce_str=5K8264ILTKCH16CQ2502SI8ZNMTM6
7VS¬ify_url=http://www.weixin.qq.com/wxpay/pay.php&
openid=oUpF8uMuAJO_M2pxb1Q9zNjWeS6o&out_trade_no=2015080
6125346&spbill_create_ip=123.12.12.123&total_fee=88&trad
e_type=JSAPI&key=1a79a4d60de6718e8e5b326e338ae533
複製代碼
此字符串的MD5碼的大寫就是sign。由於上面的total_fee與spbill_create_ip咱們還沒處理,因此這個數據放到下面再處理。
MD5碼示例值
C380BEC2BFD727A4B6845133519F3AD6
到此爲止你的雲函數結構應該爲:
payment
|__index.js
|__package.json
|__random.js
複製代碼
其中index.js的內容應該爲:
//雲函數入口文件
const cloud = require('wx-server-sdk')
cloud.init()
const openid = cloud.getWXContext().OPENID
const appid = 'wxwxd678efh567hg6787'
const mch_id = '1230000109'
const random = require('random.js')
const body = "騰訊-遊戲"
const notify_url = 'http://www.weixin.qq.com/wxpay/pay.php'
const trade_type = 'JSAPI'
const key = '1a79a4d60de6718e8e5b326e338ae533'
//雲函數入口函數
exports.main = async (event, content) => {
const out_trade_no = Date.parse(new Date()).toString()
}
複製代碼
接下來咱們處理上面沒有處理的total_fee與spbill_create_ip,以及sign。 其中total_fee和spbill_create_ip是由客戶端上傳的,這兩個數據就在雲函數入口函數的參數event中,因此咱們在雲函數入口函數裏面加上如下代碼
const total_fee = event.total_fee
const spbill_create_ip = event.spbill_create_ip
複製代碼
最後,咱們須要處理sign,按照12.sign提到的規則,在雲函數入口函數裏面加上如下代碼
let stringA = `appid=${appid}&body=${body}& mch_id=${mch_id}&nonce_str=${random}& 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}& key=1a79a4d60de6718e8e5b326e338ae533`
複製代碼
咱們如今須要將這個字符串進行MD5碼加密,因此須要安裝一個npm包來完成這個任務。右鍵點擊雲函數pyament,選擇「在終端打開」,輸入下面的命令:
npm install --save crypto
複製代碼
完成後在雲函數入口文件處加上如下代碼
const crypto = require("crypto")
複製代碼
這樣咱們就成功地將crypto這個加密工具包引入咱們的雲函數裏了。而後咱們須要在雲函數入口函數裏使用它對剛剛的stringA進行MD5加密。因此咱們在let stringA = ...
這行代碼下面添加如下代碼
var sign = crypto.createHash('md5').update(stringA).digest('hex').toUpperCase()
複製代碼
咱們如今須要將這些數據轉成xml格式,例如:
<xml>
<appid>wxd930ea5d5a258f4f</appid>
<mch_id>10000100</mch_id>
<device_info>1000</device_info>
<body>test</body>
<nonce_str>ibuaiVcKdpRxkhJA</nonce_str>
<sign>9A0A8659F005D6984697E2CA0A9CF3B7</sign>
...
</xml>
複製代碼
在雲函數中新建一個requestData.js,寫下以下函數,用來完成將數據轉成xml的任務
function requestData( appid, mch_id, nonce_str, sign, body, out_trade_no, total_fee, spbill_create_ip, notify_url, trade_type, openid ){
let data = "<xml>"
data += "<appid>"+appid+"</appid>"
data += "<mch_id>"+mch_id+"</mch_id>"
data += "<nonce_str>"+nonce_str+"</nonce_str>"
data += "<sign>"+sign+"</sign>"
data += "<body>"+body+"</body>"
data += "<out_trade_no>"+out_trade_no+"</out_trade_no>"
data += "<total_fee>"+total_fee+"</total_fee>"
data += "<spbill_create_ip>"+spbill_create_ip+"</spbill_create_ip>"
data += "<notify_url>"+notify_url+"</notify_url>"
data += "<trade_type>"+trade_type+"</trade_type>"
data += "<openid>"+openid+"</openid>"
data += "</xml>"
return data
}
module.exports = requestData
複製代碼
此時雲函數的結構爲
payment
|__index.js
|__package.json
|__package-lock.json //由npm install產生的文件
|__random.js
|__requestData.js
複製代碼
咱們須要將requestData.js文件導入到咱們的項目。在雲函數入口文件那裏添加如下代碼
const requestData = require("requestData.js")
複製代碼
如今,咱們能夠生成調用支付統一下單API的訂單了,這個dataBody就是訂單。
let dataBody = reqData(
appid,
mch_id,
random,
sign,
body,
out_trade_no,
total_fee,
spbill_create_ip,
notify_url,
trade_type,
openid
)
複製代碼
咱們須要對官方提供的連接https://api.mch.weixin.qq.com/pay/unifiedorder
發起統一下單,因此這裏咱們須要一個npm包來幫咱們完成request請求,而且因爲發起請求後的返回值是xml格式的,因此咱們還須要一個npm包來幫助咱們解析xml格式文件。故右鍵點擊雲函數payment,選擇「在終端打開」,輸入下面命令:
npm install --save request
npm install --save xmlreader
複製代碼
在雲函數入口文件中引入上面兩個包:
const request = require("request")
const xmlreader = require("xmlreader")
複製代碼
而後就能夠在雲函數入口函數中發起對統一下單API的request請求了,因爲request是異步請求,因此咱們須要返回一個Promise。
return new Promise(reslove => {
request({
//官方統一下單api的url
url: 'https://api.mch.weixin.qq.com/pay/unifiedorder',
//請求方法,post
method: "POST",
//須要傳送的訂單,就是剛剛咱們生成的dataBody
body: dataBody
}, body => {
//body就是咱們收到的數據,咱們須要獲得其中的prepay_id
//使用xmlreader解析body,得到其中的prepay_id
xmlreader.read(body, res => {
//此時咱們已經完成第三步的目的了
let prepay_id = res.xml.prepay_id.text()
}
}
}
複製代碼
已知wx.requestPayment()須要五個參數,分別是
其中,timeStamp爲時間戳,可由Date.parse(new Date()).toString()
取得。 nonceStr爲隨機字符串,可由咱們的隨機函數取得。 package就是上一步得到的prepay_id, signType是簽名類型,咱們選擇的是MD5。因此咱們如今只剩下paySign未知,獲得paySign的方法爲
paySign = MD5(appId=wxd678efh567hg6787&nonceStr=5K826
4ILTKCH16CQ2502SI8ZNMTM67VS&package=prepay_id=wx20170
33010242291fcfe0db70013231072&signType=MD5&timeStamp=
1490840662&key=qazwsxedcrfvtgbyhnujmikolp111111) = 22D
9B4E54AB1950F51E0649E8810ACD6
複製代碼
因此咱們在上一步的代碼中接着寫
return new Promise(reslove => {
request({
url: 'https://api.mch.weixin.qq.com/pay/unifiedorder',
method: "POST",
body: dataBody
}, body => {
xmlreader.read(body, res => {
let prepay_id = res.xml.prepay_id.text()
let timeStamp = Date.parse(new Date()).toString()
let str = `appId=${appid}&nonceStr=${random}&package=prepay_id=${prepay_id}&signType=MD5&timeStamp=${timeStamp}&key=1a79a4d60de6718e8e5b326e338ae533`
let paySign = crypto.createHash('md5').update(str).digest('hex')
//返回上面的五個參數
reslove({
data: {
timeStamp: timeStamp,
nonceStr: random,
package: `prepay_id=${prepay_id}`,
signType: 'MD5',
paySign: paySign
}
})
}
}
}
複製代碼
此時雲函數結構爲:
payment
|__index.js
|__package.json
|__package-lock.json
|__random.js
|__requestData.js
複製代碼
index.js:
//雲函數入口文件
const cloud = require('wx-server-sdk')
cloud.init()
const openid = cloud.getWXContext().OPENID
const appid = 'wxwxd678efh567hg6787'
const mch_id = '1230000109'
const random = require('random.js')
const body = "騰訊-遊戲"
const notify_url = 'http://www.weixin.qq.com/wxpay/pay.php'
const trade_type = 'JSAPI'
const key = '1a79a4d60de6718e8e5b326e338ae533'
const crypto = require("crypto")
const requestData = require("requestData")
const request = require("request")
const xmlreader = require("xmlreader")
//雲函數入口函數
exports.main = async (event, content) => {
const out_trade_no = Date.parse(new Date()).toString()
const total_fee = event.total_fee
const spbill_create_ip = event.spbill_create_ip
let stringA = `appid=${appid}&body=${body}&mch_id=${mch_id}&nonce_str=${random}¬ify_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}&key=1a79a4d60de6718e8e5b326e338ae533`
var sign = crypto.createHash('md5').update(stringA).digest('hex').toUpperCase()
let dataBody = reqData(
appid,
mch_id,
random,
sign,
body,
out_trade_no,
total_fee,
spbill_create_ip,
notify_url,
trade_type,
openid
)
return new Promise(reslove => {
request({
url: 'https://api.mch.weixin.qq.com/pay/unifiedorder',
method: "POST",
body: dataBody
}, body => {
xmlreader.read(body, res => {
let prepay_id = res.xml.prepay_id.text()
let timeStamp = Date.parse(new Date()).toString()
let str = `appId=${appid}&nonceStr=${random}&package=prepay_id=${prepay_id}&signType=MD5&timeStamp=${timeStamp}&key=1a79a4d60de6718e8e5b326e338ae533`
let paySign = crypto.createHash('md5').update(str).digest('hex')
//返回上面的五個參數
reslove({
data: {
timeStamp: timeStamp,
nonceStr: random,
package: `prepay_id=${prepay_id}`,
signType: 'MD5',
paySign: paySign
}
})
}
}
}
複製代碼
random.js:
function random(){
var result = ''
const wordList = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '1', '2',
'3', '4', '5', '6', '7', '8', '9', '0']
for(let i=0;i<31;i++){
result += wordList[Math.round(Math.random()*36)]
}
return result
}
module.exports = random()
複製代碼
requestData.js:
function requestData( appid, mch_id, nonce_str, sign, body, out_trade_no, total_fee, spbill_create_ip, notify_url, trade_type, openid ){
let data = "<xml>"
data += "<appid>"+appid+"</appid>"
data += "<mch_id>"+mch_id+"</mch_id>"
data += "<nonce_str>"+nonce_str+"</nonce_str>"
data += "<sign>"+sign+"</sign>"
data += "<body>"+body+"</body>"
data += "<out_trade_no>"+out_trade_no+"</out_trade_no>"
data += "<total_fee>"+total_fee+"</total_fee>"
data += "<spbill_create_ip>"+spbill_create_ip+"</spbill_create_ip>"
data += "<notify_url>"+notify_url+"</notify_url>"
data += "<trade_type>"+trade_type+"</trade_type>"
data += "<openid>"+openid+"</openid>"
data += "</xml>"
return data
}
module.exports = requestData
複製代碼