從前端的(de)角度來(lái)梳理微信支付(小程序、H5、JSAPI)的(de)流程 - 新聞資訊 - 雲南小程序開發|雲南軟件開發|雲南網站建設-昆明融晨信息技術有限公司

159-8711-8523

雲南網建設/小程序開發/軟件開發

知識

不(bù)管是(shì)網站,軟件還是(shì)小程序,都要(yào / yāo)直接或間接能爲(wéi / wèi)您産生價值,我們在(zài)追求其視覺表現的(de)同時(shí),更側重于(yú)功能的(de)便捷,營銷的(de)便利,運營的(de)高效,讓網站成爲(wéi / wèi)營銷工具,讓軟件能切實提升企業内部管理水平和(hé / huò)效率。優秀的(de)程序爲(wéi / wèi)後期升級提供便捷的(de)支持!

您當前位置>首頁 » 新聞資訊 » 小程序相關 >

從前端的(de)角度來(lái)梳理微信支付(小程序、H5、JSAPI)的(de)流程

發表時(shí)間:2021-1-5

發布人(rén):融晨科技

浏覽次數:152

因業務需要(yào / yāo),開發微信支付功能,涉及三種支付方式:

  • JSAPI 支付:微信内網頁支付,需要(yào / yāo)開通微信服務号
  • 小程序支付:在(zài)小程序中支付,需要(yào / yāo)開通小程序
  • H5 支付:在(zài)手機浏覽器(出(chū)微信内網爺)中網頁支付

使用微信支付的(de)前提必開通微信商戶号,要(yào / yāo)使用到(dào)那種的(de)支付方式要(yào / yāo)前需在(zài)商戶平台開通(要(yào / yāo)審核)。

支付的(de)錢最終都會到(dào)商戶号裏(一般由公司财務開通)。

開發微信支付的(de)過程中大(dà)大(dà)小小坑還是(shì)踩了(le/liǎo)不(bù)少,終于(yú)做完了(le/liǎo),整理下開發流程。

參考:

  • 微信支付-接入指引
  • 微信支付-開發文檔

小程序支付

開發流程

  1. 小程序端請求創建訂單接口,後端統一下單獲取 orderId 并返回
  2. 小程序端獲取通過wx.login()獲取code
  3. 小程序端拿這(zhè)code和(hé / huò)orderId請求後端接口,獲取支付所需數據
  4. 獲取支付所需數據之(zhī)後,小程序端調用wx.requestPayment()接口,直接調用起支付頁面
  5. 判斷是(shì)否支付成功後的(de)邏輯

僞代碼

async function wxPay(goodId) {
  // 1. 創建訂單 獲取orderId
  let orderId = await ajax("POST", "/api/OrderProgram/CreateTheOrder", {
    goodId, // 商品id
  });
  // 2. 獲得 code
  let code = await wxlogin(); // 基于(yú)pr封裝的(de)wx.login()方法
  // 3. 獲取支付的(de)數據
  let payData = http://www.wxapp-union.com/await ajax("POST", "/api/OrderProgram/WxXcxPay", {
    orderId,
    code,
  });
  // 4. 發起支付
  let res = await payment(payData); // 基于(yú)pr封裝的(de)wx.requestPayment()方法
  // 5. 判斷是(shì)否支付成功
  let payResult = res.errMsg;
  if (payResult == "requestPayment:ok") {
    console.log("支付成功");
  } else if (payResult == "requestPayment:fail cancel") {
    console.log("用戶取消支付");
  } else {
    console.log("支付失敗");
  }
}

注意事項

  1. 申請微信小程序賬号
    申請成功可拿到(dào) AppID(小程序 id)和(hé / huò) AppSecret(小程序密鑰)
    申請類型爲(wéi / wèi)企業性質,否則無法接入微信支付
  2. 微信小程序認證
    通過認證的(de)小程序才能接入微信支付和(hé / huò)綁定商戶平台
  3. 申請商戶平台賬号
    需要(yào / yāo)第一步申請的(de) AppID
    申請成功可拿到(dào) MchID(商戶 id)和(hé / huò) MchKey(商戶密鑰)
  4. 信小程序關聯商戶号
    微信和(hé / huò)商戶都認證成功後,在(zài)微信後台微信支付菜單中進行關聯
  5. 接入微信支付
    在(zài)微信後台微信支付菜單中進行接入

參考

  • 小程序支付文檔
  • 小程序開發文檔

H5 支付

開發流程

  1. 前端端請求創建訂單接口,後端統一下單獲取 orderId 并返回
  2. 前端帶着 orderId 請求支付接口,獲得 mweb_url
  3. 然後跳轉 mweb_url 會跳轉微信自動調用微信支付
  4. 支付後返回支付頁,判斷是(shì)否支付成功(需發送請求後端查詢)
    4.1 刷新頁面,獲取最新的(de)支付(訂單)狀态。
    4.2 設置一個(gè)的(de)按鈕"我已支付",讓用戶點擊自動查詢狀态。

僞代碼

async function wxH5Pay(goodId) {
  // 1. 創建訂單 獲取orderId
  let orderId = await ajax("POST", "/api/OrderProgram/CreateTheOrder", {
    goodId, // 商品id
  });
  // 2. 獲取支付跳轉的(de)URL
  let mweb_url = await ajax("POST", "/api/OrderProgram/WxH5Pay", { orderId });
  // 3. 跳轉URL去微信支付
  if (mweb_url) {
    location.href = http://www.wxapp-union.com/mweb_url;
  } else {
    console.log("回調地(dì / de)址出(chū)錯");
  }
  // 4. 支付後返回支付頁,判斷是(shì)否支付成功
  // 4.1 刷新頁面,獲取最新的(de)訂單(商品)狀态。
  // 4.2 設置一個(gè)"我已支付"的(de)按鈕,讓用戶點擊之(zhī)後查詢狀态。
}

注意事項

  • 在(zài)商戶平台設置正确的(de)支付域名
  • 調試需要(yào / yāo)在(zài)線上(shàng),如果嫌麻煩可以(yǐ)使用内網穿透(Ngrok 或花生殼)
  • 需對redirect_url進行urlencode處理
  • H5 支付不(bù)能直接在(zài)微信客戶端内調起,請在(zài)外部浏覽器調起。

參考

  • 微信支付-H5 支付-開發步驟

JSAPI 支付(微信内網頁支付)

開發流程

  • 商品頁
  1. 前端商品頁創建訂單,在(zài)後端統一下單後獲取 orderId
  2. 前端帶着 orderId 跳轉到(dào)支付頁,
  • 支付頁
  1. 獲取 code

    1. 第一次進入頁面,判斷是(shì)否路徑中有 code
    2. 沒有 code,請求數據跳轉授權頁面,code 會通過回調地(dì / de)址一起返回回來(lái)
    3. 拿到(dào) code,發送給後端,後端解析到(dào) openid,保存好。
  2. 點擊确定支付按鈕,觸發 wxPay() 方法

    1. 發送 orderId 給後端,獲取 wxData
    2. wxData 中包含 wx.config 和(hé / huò) wx.chooseWXPay 兩個(gè)接口的(de)數據。
    3. 先調用 wx.config()然後在(zài)調用 wx.chooseWXPay(),如果一切正常,支付頁面就(jiù)會彈出(chū)。
  3. 支付狀态通過後端去查詢

僞代碼

  • 商品頁
// 1. 創建訂單 獲取orderId
let orderId = await ajax("POST", "/api/OrderProgram/CreateTheOrder", {
  goodId, // 商品id
});
// 2. 攜帶id 跳轉到(dào)支付頁
this.$router.push({ name: "wx_pay_page", params: { orderId: id } });
  • 入口文件(main.js)
// main.js 引入 js-sdk
import wx from "weixin-js-sdk";
  • 支付頁 HTML
<template>
  <div>
    <button @click="wxPay">點擊支付button>
  div>
template>

支付頁 JS

// Vue
data(){
    return {
        orderId: this.$route.params.orderId, // 訂單id
        url: '',// 獲取code的(de)url
        wxData: null,// js-sdk接口所需的(de)數據
    }
},
mounted(){
    // 判斷是(shì)否有code
    this.getCode()
}
methods: {
    getCode() {
        var code = this.getUrlPram("code");
        if (code != null) {
            this.code = code;
            // 拿到(dào) code 發給 後端
            this.sendCode(code);
        } else {
            // 去拿code
            this.getUrl();
        }
    },
    getUrl() {
        // 請求後端拿到(dào)url所需數據,然後跳轉頁面在(zài)通過回調地(dì / de)址返回,獲取code.
        this.axios
            .post("/api/OrderProgram/GetOpenidAndAccessToken", {
                orderId: this.orderId,
            })
            .then((data) => {
                this.url = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${data.appId}&redirect_uri=${data.redirect_uri}&response_type=${data.response_type}&scope=${data.scope}&state=${data.state}`;
                window.location.href = http://www.wxapp-union.com/this.url;
            })
            .catch((err) => {
                console.log(err);
            });
    },
    sendCode(code) {
        // 發送code給後端 後端解析出(chū)openid
        this.axios
            .post("/api/OrderProgram/GetOpenidAndAccessTokenFromCode", {
                code: code,
            })
            .then((res) => {
                console.log(res);
            })
            .catch((err) => {
                console.log(err);
            });
    },
    wxPay: async function() {
        // 發送orderid,獲取wx.chooseWXPay和(hé / huò)wx.config所需的(de)參數
        this.wxData = http://www.wxapp-union.com/await this.axios.post(
            "/api/OrderProgram/WxJSAPIPay",
            { orderId: this.orderId }
        );
        let wxConfigData = http://www.wxapp-union.com/this.wxData.wxConfigData // 獲取wx.chooseWXPay()所需數據
        let wxPayData = http://www.wxapp-union.com/this.wxData.wxPayData;// 獲取wx.config()所需數據
        this.$wx.config({
            debug: false, // 開啓調試模式,調用的(de)所有api的(de)返回值會在(zài)客戶端alert出(chū)來(lái),若要(yào / yāo)查看傳入的(de)參數,可以(yǐ)在(zài)pc端打開,參數信息會通過log打出(chū),僅在(zài)pc端時(shí)才會打印。
            appId: wxConfigData.appId, // 必填,公衆号的(de)唯一标識
            timestamp: wxConfigData.timeStamp, // 必填,生成簽名的(de)時(shí)間戳
            nonceStr: wxConfigData.nonceStr, // 必填,生成簽名的(de)随機串
            signature: wxConfigData.paySign, // 必填,簽名
            jsApiList: [
                "chooseWXPay",
            ],
        });
        // 執行支付
        this.$wx.chooseWXPay({
            timestamp: wxPayData.timeStamp, // 支付簽名時(shí)間戳,注意微信jssdk中的(de)所有使用timestamp字段均爲(wéi / wèi)小寫。但最新版的(de)支付後台生成簽名使用的(de)timeStamp字段名需大(dà)寫其中的(de)S字符
            nonceStr: wxPayData.nonceStr, // 支付簽名随機串,不(bù)長于(yú) 32 位
            package: wxPayData.package, // 統一支付接口返回的(de)prepay_id參數值,提交格式如:prepay_id=\*\*\*)
            signType: wxPayData.signType, // 簽名方式,默認爲(wéi / wèi)'SHA1',使用新版支付需傳入'MD5'
            paySign: wxPayData.paySign, // 支付簽名
            success: (res) => {
                this.$toast("支付成功");
            },
            fail: (err) => {
                this.$toast("支付失敗");
            },
        });
    },
}

同時(shí)支持 H5 支付和(hé / huò) JSAPI 支付

// 在(zài)創建訂單之(zhī)後,就(jiù)判斷環境使用哪種方法支付。
if (isWx()) {
  this.WXPay(orderId); // 帶着orderId跳轉到(dào)支付頁邏輯
} else {
  this.H5Pay(orderId); // 執行上(shàng)面H5支付中的(de)創建訂單之(zhī)後的(de)邏輯
}
// 判斷是(shì)否是(shì)微信浏覽器
function isWx() {
  let uAgent = navigator.userAgent.toLowerCase();
  reutrn(/micromessenger/.test(uAgent)) ? true : false;
}

注意事項

  • 開通微信商戶号 - 設置支付目錄(如果是(shì) Vue 這(zhè)類 SPA 頁面,到(dào)根目錄即可,也(yě)就(jiù)是(shì)#号之(zhī)前的(de)地(dì / de)址)

  • 開通微信公衆号(服務号) - 設置安全域名、設置授權域名

  • 收集參數:appId 和(hé / huò) AppSecret
  • 添加 Web 開發工具開發者(需要(yào / yāo)開發者同時(shí)開發者關注開發的(de)微信公衆号和(hé / huò)微信公衆賬号安全助手)
    [圖片上(shàng)傳失敗...(image-b07878-1605777597831)]
  • 設置回調域名(例如:www.xx.com/pay,最後獲取的(de) code 會拼在(zài)此回調地(dì / de)址後返回,返回後如www.xx.com/pay?code=xxxx
    wxpay5.png
  • 獲取 code

    • 參考獲取 code 文檔
    • 在(zài)微信客戶端網頁打開授權地(dì / de)址,跳轉之(zhī)後,在(zài)返回的(de)回調地(dì / de)址之(zhī)後拿到(dào) code
https://open.weixin.qq.com/connect/oauth2/authorize
?appid=你的(de)appid
&redirect_uri=你的(de)回調地(dì / de)址(拿到(dào)code後返回)
&response_type=code(返回類型,默認code)
&scope=snsapi_base(授權範圍,靜默授權拿到(dào)openid)
&state=STATE(自定義狀态,非必填)
#wechat_redirect(重定向使用必須攜帶)

redirect_uri參數要(yào / yāo)和(hé / huò)你在(zài)微信公衆号裏設置的(de)回調域名一緻(例如:www.xx.com/pay),需要(yào / yāo)注意的(de)是(shì)這(zhè) url 需要(yào / yāo)urlEncode

請求這(zhè)個(gè)地(dì / de)址之(zhī)後,code 會以(yǐ)你設置的(de)redirect_uri地(dì / de)址裏的(de)參數帶回來(lái),拿到(dào)之(zhī)後傳給後端就(jiù)行了(le/liǎo)。

  • 前端引入 js-skd

    • 使用script引入js-sdk
    • 下載使用 npm 包weixin-js-sdk

參考

  • 微信支付-JSAPI
  • 微信公衆号-網頁授權
  • JS-SDK 開發文檔

總結

整個(gè)流程走下來(lái),給我的(de)體驗是(shì):小程序支付最方面(因爲(wéi / wèi)配置少),其次是(shì) H5,JSAPI 支付最麻煩(文章一多半都在(zài)寫它)

在(zài)微信支付功能開發過程中,其實最麻煩的(de)不(bù)是(shì)開發流程,而(ér)是(shì)他(tā)的(de)各種配置和(hé / huò)授權流程,爲(wéi / wèi)了(le/liǎo)拿到(dào)所需的(de)參數而(ér)來(lái)回折騰。

開發過程中的(de)一些參數是(shì)經常用到(dào)的(de),如 appid、openid、orderId

支付流程大(dà)徑相同,先獲取到(dào)用戶的(de) openid,知道(dào)你是(shì)誰,然後統一下單拿到(dào) orderId 再去處理不(bù)同平台的(de)支付方式

開發時(shí)候用到(dào)的(de)相關文檔,一定要(yào / yāo)仔細閱讀二遍以(yǐ)上(shàng)爲(wéi / wèi)止!!

相關案例查看更多