node微信支付踩坑日記(公衆號支付)

前言:花了好幾天的時間搞了下微信公衆號支付,期間歷程無比心酸,總的來說還是理解能力不夠和經驗不足,現在歸納下支付中遇到的坑。

先看業務流程
圖片描述

前期猜想及準備工作

首先,公衆號支付採用的是,利用微信的js-sdk調起支付的方式進行的,其中分爲兩種情況:微信jssdk調起和微信支付開放平臺調起。但是,無論是採用什麼方法首先都要先配置wx.config。

wx.config({
    debug: true, // 開啓調試模式,調用的所有api的返回值會在客戶端alert出來,若要查看傳入的參數,可以在pc端打開,參數信息會通過log打出,僅在pc端時纔會打印。
    appId: '', // 必填,公衆號的唯一標識
    timestamp: , // 必填,生成簽名的時間戳
    nonceStr: '', // 必填,生成簽名的隨機串
    signature: '',// 必填,簽名
    jsApiList: [] // 必填,需要使用的[JS接口列表][4],chooseWXPay 微信支付接口
});

參數分析:appId,timestamp,nonceStr 這裏需要注意一下變量的大小寫,這裏採用的是駝峯命名法,timestamp因爲本身就是一個單詞,所以不要寫錯。signature這個需要注意一下,畢竟涉及到的 sign(簽名)、token 實在太多了,極其容易混淆。同時,生成簽名之前必須先了解一下jsapi_ticket,jsapi_ticket是公衆號用於調用微信JS接口的臨時票據。正常情況下,jsapi_ticket的有效期爲7200秒,通過access_token來獲取,獲取jsapi_ticket的api調用次數非常有限,頻繁刷新jsapi_ticket會導致api調用受限,影響自身業務,開發者必須在自己的服務全局緩存jsapi_ticket ,然而access_token的有效期也只有7200秒,所以把jsapi_ticket和access_token同時緩存(當然你可以只存jsapi_ticket) 。這裏推薦參數從後臺獲取,代碼如下:

{
  const  moment = require('moment'), //時間處理類  cnpm i moment
         request = require("request"); //cnpm i request  https://github.com/request/request
         wxConfig = {
             appid:'', //appid
             appsecret:'', //appsecret
             mcnsecret:'', //商戶key
             mcnid:'', //商戶號
             notify_url:'' //支付成功想要回調的後臺地址,用於修改訂單狀態等等操作
         }
  // 獲取 公衆號的access_token和ticket ,需要存入緩存或者數據庫,有效期7200s,請注意和獲取用戶access_token api進行區分
  app.get('/accpetSubscriptionNow',async function (req,res,next) {
    let task = await XXXXModel.findOne({where:where});//獲取存在數據庫裏面的公衆號的accesstoken,XXXXModel是自己的表
    let cc = {};
    let WXInitConfig = {};//創建一個空對象用以存儲微信公衆號配置信息
    // 判斷數據庫裏面是否存在accesstoken等信息,且存放的時間是否超過7200秒
    if(JSON.stringify(task.updateBy)==='{}' || parseInt(moment(task.updateBy.updateTime).format('X')) + 7200 < parseInt(moment().format('X'))){
      console.log('#1.判斷accesstoken的更新時間大於7200s,重新拉取accesstoken')
      request.get(
        {
          // 獲取access_token的接口
          url: `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${wxConfig.appid}&secret=${wxConfig.appsecret}`
        },
        async function (error, response, body) {
          console.log('body', body)
          //成功獲取到access_token,這裏應該有個判斷
          const ACCESS_TOKEN = JSON.parse(response.body).access_token;
          let  json = JSON.parse(response.body);
          request.get({
            // 獲取jsapi_ticket的接口
            url: `https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=${ACCESS_TOKEN}&type=jsapi`
          },
          async function (error, response, body) {
            //成功獲取到jsapi_ticket,這裏應該有個判斷
            console.log('body2', body)
            let updateBy = {
              updateTime : new Date()
            }
            json.ticket = JSON.parse(body).ticket;
            // 把獲取到的access_token和jsapi_ticket存放到數據庫,並標明更新時間
            cc = await XXXXModel.findOneAndUpdate({
              where:where
            }, {data: data})
            
            WXInitConfig = cc.content;
            //console.log('WXInitConfig',WXInitConfig)
            let data = await acceptsignature(WXInitConfig);
            //console.log('data',data)
            res.send(data);//傳遞微信號配置信息到前端
          })
        }
      )
    }else {
      console.log('#2.判斷accesstoken的更新時間小於7200s,從數據庫獲取access_token和ticket')
      WXInitConfig = task.content;
      let data = await acceptsignature(WXInitConfig);
      res.send(data);
    }
  })
  
  // 獲取signature簽名的方法
  function acceptsignature(WXInitConfig) {
    console.log('WXInitConfig2',WXInitConfig)
    let appid = wxConfig.appid;
    let nonceStr = Math.random().toString(36).substr(2, 15);
    let access_token = WXInitConfig.access_token;
    let jsapi_ticket = WXInitConfig.ticket;
    let timestamp = moment().format('X');
    let url = 'http://mmobile.hwason.cn/';
    
    // 把所需的參數ASCII序列化
    let ASC = `jsapi_ticket=${jsapi_ticket}&noncestr=${nonceStr}&timestamp=${timestamp}&url=${url}`;
    console.log('ASCII',ASC)
    // 把序列化的數據使用 SHA1 方法加密,記住得到的是小寫的加密串
    let signature = SHA1(ASC).toLowerCase();
    console.log('signature',signature)
    let data = {
      appid:appid,
      nonceStr:nonceStr,
      // access_token:access_token,
      // jsapi_ticket:jsapi_ticket,
      timestamp:timestamp,
      // url:url,
      signature:signature,
      result:'00'
    }
    return data;
  }
}

到此,前端調用上述的接口就可以獲取到微信的配置參數了。
參數配置好了,就開始正式啓動微信公衆號支付了。

步驟①:設置支付目錄
步驟②:設置授權域名
步驟③:前臺進入微信授權頁面
微信授權又分爲5步:
1)進入微信授權頁,用戶同意授權,獲取code

//進入授權頁有兩張方式
// 一、前端直接跳轉
let return_url = ''; //授權後回調的頁面,這裏是前端的地址url
window.location.href = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx1a1cf7c547b07420&redirect_uri=" + encodeURIComponent(return_url) + "&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect"
// 二、後端重定向

//尤其注意:由於授權操作安全等級較高,所以在發起授權請求時,微信會對授權鏈接做正則強匹配校驗,如果鏈接的參數順序不對,授權頁面將無法正常訪問


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章