關(guān)于微信小程序?qū)崿F(xiàn)云支付那些事兒
一、前言
稍微玩過微信小程序云開發(fā)的同學(xué)都基本知道微信小程序云開發(fā)目前已經(jīng)支持云支付這一能力。
那么在云支付的能力支持之下,整個支付的流程是怎樣的呢?
例如:用戶發(fā)起支付前、支付中、支付后的邏輯處理應(yīng)該是怎樣的,該如何設(shè)計會比較保險,降低出錯的概率。
那么本文主要介紹云支付的使用以及在云支付下的訂單系統(tǒng)、支付流程該如何設(shè)計。
順便提一下:微信支付功能僅支持企業(yè)主體調(diào)用。
二、思路分析
云支付的調(diào)用流程大致分為以下四步:
1、獲取免鑒權(quán)參數(shù)
小程序端傳入金額、商品信息等基本參數(shù)后,調(diào)用云函數(shù)獲取免鑒權(quán)參數(shù)。
2、將免鑒權(quán)參數(shù)傳入小程序端的支付API
云函數(shù)返回免鑒權(quán)參數(shù),作為小程序端支付API的入?yún)ⅰ?/p>
3、用戶支付
調(diào)起微信支付,用戶進行支付/取消支付操作
4、微信端回調(diào)指定的云函數(shù)
支付成功后回調(diào)此云函數(shù)。
如果用戶取消支付,則不會回調(diào)此云函數(shù)。
那么,根據(jù)以上四個步驟就可以分析出,訂單的創(chuàng)建、訂單支付狀態(tài)的改變應(yīng)該是在什么時候了。
訂單的創(chuàng)建應(yīng)該是在第一步的獲取免鑒權(quán)參數(shù)的時候,獲取免鑒權(quán)參數(shù)后將訂單號等信息插入數(shù)據(jù)庫。
此時的訂單支付狀態(tài)應(yīng)該是待支付狀態(tài)。
同時也可以知道,訂單支付狀態(tài)的改變,應(yīng)該是在第四步中去進行改變,如果支付成功,將訂單的支付狀態(tài)改為支付成功即可。
相關(guān)的官方文檔鏈接:
三、云支付小案例
1.云函數(shù)
1-1.獲取免鑒權(quán)參數(shù)云函數(shù)(wxPay)
此云函數(shù)主要是獲取支付API所需的參數(shù),以及創(chuàng)建訂單插入數(shù)據(jù)庫。
成功調(diào)用示例結(jié)果截圖
實現(xiàn)代碼
// 云函數(shù)入口文件 const cloud = require('wx-server-sdk') cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV }) const db = cloud.database() exports.main = async (event) => { const wxContent = cloud.getWXContext() // openid等信息 const openid = wxContent.OPENID const appid = wxContent.APPID const totalFee = event.totalFee // 支付金額(單位:分) const body = event.body // 商品名 const outTradeNo = createOutTradeNo() // 訂單號 // 獲取免鑒權(quán)支付參數(shù) const payMent = await cloud.cloudPay.unifiedOrder({ "body": body, "outTradeNo": outTradeNo, "spbillCreateIp": "127.0.0.1", "subMchId": "商戶號", // 商戶號 "totalFee": totalFee, "envId": "對應(yīng)的云環(huán)境id", // 云環(huán)境id "functionName": "payCallBack" // 支付回調(diào)云函數(shù) }) // 創(chuàng)建訂單 const nowTime = new Date().getTime() const orderObj = { _openid: openid, appid: appid, outTradeNo: outTradeNo, totalFee: totalFee * 0.01, payStatus: 'wait', createTime: nowTime, updateTime: nowTime, deleteTime: null, } await addOrder(orderObj) return payMent } /** 創(chuàng)建隨機的唯一訂單號(32位) */ const createOutTradeNo = () => { let outTradeNo = new Date().getTime() // 獲取當(dāng)前13位時間戳 let numStr = '0123456789'; let randomStr = ''; for (let i = (32 - 13); i > 0; --i) { randomStr += numStr[Math.floor(Math.random() * numStr.length)]; } outTradeNo += randomStr return outTradeNo } /** 向數(shù)據(jù)庫創(chuàng)建訂單 */ const addOrder = async (orderObj) => { return await db.collection('order') .add({ data: orderObj }) .then(res => { console.log("創(chuàng)建訂單成功 =====>", res, orderObj) }) .catch(err => { console.log("創(chuàng)建訂單異常 =====>", err, orderObj) }) }
1-2.支付回調(diào)云函數(shù)(payCallBack)
在用戶支付成功后微信服務(wù)端將會調(diào)用此云函數(shù),并攜帶支付方的訂單號、openid、appid等信息。
開發(fā)者可以根據(jù)這個來判斷當(dāng)前回調(diào)的是哪個訂單。
成功回調(diào)結(jié)果示例截圖
實現(xiàn)代碼
// 云函數(shù)入口文件 const cloud = require('wx-server-sdk') cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV }) const db = cloud.database() // 云函數(shù)入口函數(shù) exports.main = async (event) => { console.log("回調(diào)返回對象 =====>", event) // 判斷條件 if (event.returnCode == 'SUCCESS') { if (event.resultCode == 'SUCCESS') { // 查詢條件 const whereObj = { appid: event.subAppid, // 小程序的APPID _openid: event.subOpenid, // 小程序用戶的openid outTradeNo: event.outTradeNo, // 商戶號的訂單號 } // 更新對象 const updateObj = { transactionId: event.transactionId, // 微信方的訂單號 totalFee: event.totalFee * 0.01, // 微信方收到的金額 timeEnd: event.timeEnd, // 支付結(jié)束時間 payStatus: 'success', updateTime: new Date().getTime() } // 更新訂單 await updateOrder(whereObj, updateObj) } } // 支付回調(diào)的返回協(xié)議和入?yún)f(xié)議(必須返回此結(jié)構(gòu)體,詳見文檔) return { errcode: 0, errmsg: event.resultCode } } /** 更新訂單的支付狀態(tài) */ const updateOrder = async (whereObj, updateObj) => { return await db.collection('order') .where(whereObj) .update({ data: updateObj }) }
2.小程序端(js代碼)
// pages/wxPay/wxPay.js Page({ /** * 頁面的初始數(shù)據(jù) */ data: { }, /** * 生命周期函數(shù)--監(jiān)聽頁面加載 */ onLoad() {}, /** * 生命周期函數(shù)--監(jiān)聽頁面顯示 */ onShow() {}, /** 支付點擊監(jiān)聽 */ async payTap() { const totalFee = 2 const body = '支付測試' wx.showLoading({ title: '調(diào)起微信支付中', mask: true }) // 獲取支付免鑒權(quán)參數(shù) const payMentRes = await this.getPayMent(totalFee, body) wx.hideLoading({ success: (res) => {}, }) // 小程序支付API const payRes = await this.wxPay(payMentRes.result.payment) // 支付API返回結(jié)果打印 console.log(payRes) }, /** * 小程序支付API * @param {object} payment 支付免鑒權(quán)參數(shù) */ wxPay(payment) { return new Promise((resolve, rejects) => { wx.requestPayment({ ...payment, success(res) { resolve({ status: 'success', res: res }) }, fail(err) { resolve({ status: 'fail', res: err }) } }) }) }, /** * 獲取支付免鑒權(quán)參數(shù) * @param {number} totalFee 支付金額, 單位:分 * @param {string} body 商品名稱 */ getPayMent(totalFee, body) { return new Promise((resolve, rejects) => { wx.cloud.callFunction({ name: 'wxPay', data: { totalFee, body }, success(res) { resolve(res) }, fail(err) { resolve(err) } }) }) }, })
3.支付結(jié)果
用戶端
商家端
4、代碼目錄結(jié)構(gòu)
四、為什么這樣寫
或許有的同學(xué)也使用過微信云支付的能力,但是不曾使用到上面說到的支付回調(diào)云函數(shù)。
但是也可以做到獲取用戶的支付結(jié)果。
如下圖
事實上,小程序端的支付API(
wx.requestPayment())
也可以返回當(dāng)前的支付結(jié)果。也確實可以使用這個回調(diào)的結(jié)果來判斷支付是否成功。
那既然這樣,為什么還要多此一舉寫個支付回調(diào)云函數(shù)來獲取支付的結(jié)果呢?
看到這里也說明你看完了整個實現(xiàn)過程了,如果你有為什么要用這種方式實現(xiàn)的疑問,也應(yīng)該多少能夠自己給自己找到一些答案。
除去開發(fā)規(guī)范、優(yōu)化相關(guān)的小問題,我這里說一個很致命的原因。
微信小程序支付API(
wx.requestPayment())
在IOS端有一個致命的問題,
當(dāng)用戶支付后會進入下面這個頁面
當(dāng)用戶不點擊完成按鈕,微信小程序的支付API(wx.requestPayment())回調(diào)是不會觸發(fā)的。
也就說,小程序自身拿不到用戶的支付結(jié)果了。
假設(shè)用戶直接退出了微信,小程序也就銷毀了。這時,訂單狀態(tài)該如何改變呢?
tips: 在安卓端不會出現(xiàn)這個問題。有興趣的同學(xué)可以自己去實踐以下。
五、結(jié)語
思路是這樣的,但是一些異常處理,需要開發(fā)者在開發(fā)過程中自行處理,例如訂單插入失敗、更新失敗等異常問題。雖然概率不大,而且也有打印調(diào)用記錄,如果出現(xiàn)問題,也是可以查到調(diào)用記錄以及相關(guān)信息。
到此這篇關(guān)于關(guān)于微信小程序?qū)崿F(xiàn)云支付那些事兒的文章就介紹到這了,更多相關(guān)微信小程序云支付內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
使用clipboard.js庫實現(xiàn)復(fù)制剪切功能
這篇文章介紹了clipboard.js實現(xiàn)復(fù)制功能的方法,文中通過示例代碼介紹的非常詳細。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-06-06javascript判斷移動端訪問設(shè)備并解析對應(yīng)CSS的方法
這篇文章主要介紹了javascript判斷移動端訪問設(shè)備并解析對應(yīng)CSS的方法,涉及移動端設(shè)備的判斷及動態(tài)加載技巧,需要的朋友可以參考下2015-02-02基于JS如何實現(xiàn)給字符加千分符(65,541,694,158)
JS如何實現(xiàn)給字符加千分符,本文給大家?guī)砹嘶趈s實現(xiàn)的代碼,代碼簡單易懂,感興趣的朋友一起學(xué)習(xí)吧2016-08-08使用CSS+JavaScript或純js實現(xiàn)半透明遮罩效果的實例分享
這篇文章主要介紹了使用CSS+JavaScript或純js實現(xiàn)半透明遮罩效果的實例分享,編寫半透明遮罩層時要注意定位問題、不要滿屏遮罩,需要的朋友可以參考下2016-05-05

JS點擊某個圖標(biāo)或按鈕彈出文件選擇框的實現(xiàn)代碼