小程序云開發(fā)也能優(yōu)雅實(shí)現(xiàn)微信支付

一喻犁、開發(fā)微信支付功能一定要架設(shè)服務(wù)器嗎?

2019年的最后一天何缓,舍得叔叔沉浸在探索的興奮中肢础,驗(yàn)證了微信小程序云開發(fā)也能優(yōu)雅實(shí)現(xiàn)微信支付!小程序的目標(biāo)是建立一個(gè)“serverless”環(huán)境碌廓,不用自行架設(shè)服務(wù)器传轰,而完全通過小程序、云函數(shù)谷婆、云存儲慨蛙、云數(shù)據(jù)庫來實(shí)現(xiàn)整個(gè)應(yīng)用功能辽聊。理念很有吸引力,就是那句話:一個(gè)人也要像一支隊(duì)伍期贫!

但是跟匆,云開發(fā)剛剛推出一年多,很多地方不夠完美通砍,方向是“去服務(wù)器”玛臂,但很多地方離開服務(wù)器就寸步難行。比如封孙,要想在小程序里面實(shí)現(xiàn)微信支付功能迹冤,連官方文檔都說開發(fā)者必須建立自己的服務(wù)器。

二敛瓷、云函數(shù)代替商戶系統(tǒng)實(shí)現(xiàn)微信支付的可行性

舍得叔叔正在開發(fā)微信租賃店叁巨,想既方便客戶使用,又方便對設(shè)備進(jìn)行管理呐籽,需要微信支付功能锋勺。但又不想為了一個(gè)支付功能跑去租服務(wù)器什么的,后期運(yùn)維也費(fèi)時(shí)費(fèi)力狡蝶,于是研究探索了一番庶橱,終于取得成功!不用架設(shè)服務(wù)器贪惹,而僅僅利用一個(gè)node.js云函數(shù)苏章,就可以實(shí)現(xiàn)微信支付的支付、退款奏瞬、查詢等全部功能枫绅。舍得叔叔把關(guān)鍵的策略和步驟記錄下來,供自己未來查看硼端,也分享給小伙伴們并淋,少走彎路珍昨。

三、微信小程序?qū)崿F(xiàn)微信支付的原理

先說微信小程序里面要實(shí)現(xiàn)微信支付功能镣典,開發(fā)者就必須同時(shí)具備2個(gè)前提條件:1、必須先開通微信支付平臺賬戶兄春,目前只有企業(yè)法人經(jīng)過認(rèn)證才能開通澎剥;2赶舆、小程序要跟微信支付平臺賬戶綁定才行趾唱。具體步驟如何,這里不累述蜻懦,官方文檔寫得很清楚。

微信支付業(yè)務(wù)是財(cái)付通公司的夕晓,這是一家人民銀行批準(zhǔn)的三方支付公司;而微信是騰訊公司的蒸辆。兩個(gè)業(yè)務(wù)主體不一樣躬贡。微信支付雖說發(fā)跡于微信,但微信支付是要讓用戶無論通過web拂玻、app、微信公眾號魄懂、還是小程序闯第,都能獲得相同的支付體驗(yàn),還要有極高的安全性填帽,符合監(jiān)管要求咙好,因此業(yè)務(wù)流程比較復(fù)雜。

這里是小程序微信支付的開發(fā)文檔:https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=7_3&index=1哀蘑。微信支付官方提供的小程序?qū)崿F(xiàn)微信支付的流程示意圖如下葵第,這只是支付功能的,發(fā)生在客戶點(diǎn)擊支付到提示支付成功期間缀台,各角色應(yīng)該做的全部工作√鸥可以看到,支付過程中辩涝,微信小程序與微信支付后臺之間勘天,有一個(gè)紅色的商戶系統(tǒng),像一道屏障把兩者隔開商膊!那么宠进,為什么微信小程序不是直接與微信后臺進(jìn)行通信,而非要弄個(gè)“商戶系統(tǒng)”在中間進(jìn)行“阻隔”实幕,況且還要讓開發(fā)者投入財(cái)力和精力為這個(gè)“阻隔”買單呢赚导?

image

這就叫“跑得了和尚,跑不了廟”凰锡!需要微信支付功能的圈暗,就要申請微信支付平臺賬戶,就要建立服務(wù)器勇哗,就要有固定IP地址(甚至必須是經(jīng)過備案的網(wǎng)址)寸齐,這是廟;而瀏覽器扰法、app這些是和尚毅厚!三方支付的角色和權(quán)責(zé)劃分得很清楚,這是人民銀行監(jiān)管部門對三方支付平臺的安全性要求祠锣。

回到微信小程序,實(shí)際上非常特別伴网,它不是別人家的應(yīng)用,而是處在微信原生環(huán)境中拳氢,是微信的一部分蛋铆。不但微信后的廟是自己的跑不了刺啦,連微信和微信小程序這些和尚也是自家造的機(jī)器人纠脾,不會亂跑。但對于微信支付業(yè)務(wù)的主體財(cái)付通而言仍然要考慮廟不是自己的糊渊,該有的流程和步驟不能省慧脱。

四、用云函數(shù)代替商戶系統(tǒng)完成微信支付

那么宗兼,能不能變通一下氮采,用云函數(shù)代替商戶系統(tǒng)呢?答案是可以主到!流程圖上躯概,商戶系統(tǒng)”支付“過程中做了3個(gè)工作:

1、配合小程序端獲得用戶的openid怔鳖;

2、生成用戶訂單度陆,并調(diào)用微信支付統(tǒng)一下單API献幔,讓微信支付為即將發(fā)生的交易預(yù)先形成一個(gè)單子,然后將返回?cái)?shù)據(jù)(5個(gè)參數(shù))進(jìn)行組合再次簽名返回給小程序蹬蚁,小程序用這5個(gè)參數(shù)就可以調(diào)用微信小程序API彈出支付對話框郑兴,完成支付;3叽粹、將支付結(jié)果推送給商戶系統(tǒng)却舀,商戶系統(tǒng)可以據(jù)此更新訂單狀態(tài)為已付款。

用一個(gè)云函數(shù)寫實(shí)現(xiàn)這幾個(gè)功能是完全可行的辆脸!尤其第1項(xiàng)工作螃诅,云函數(shù)調(diào)用的時(shí)候微信系統(tǒng)在云函數(shù)參數(shù)中就帶著openid州刽;而2和3,需要在云函數(shù)中寫一些代碼穗椅。有位小伙伴把這件事情講的很清楚匹表,值得參考:https://blog.csdn.net/gf771115/article/details/100917779。但看上去感覺還是有點(diǎn)麻煩袍镀,尤其是這僅僅是一個(gè)支付功能苇羡,其它諸如退款和付款狀態(tài)查詢等功能還要寫不少代碼。難道沒有一套類庫實(shí)現(xiàn)這些標(biāo)準(zhǔn)化的支付相關(guān)功能嗎锦茁?嘿

嘿,還真有码俩!云函數(shù)的運(yùn)行環(huán)境是node.js稿存,很多功能模塊都能在這里找到。有一個(gè)叫node-tenpay的項(xiàng)目率翅,把騰訊微信支付功能打包成類庫供其他人免費(fèi)使用袖迎,項(xiàng)目網(wǎng)址:https://github.com/befinal/node-tenpay。非常感謝這個(gè)項(xiàng)目的創(chuàng)建者,這套類庫寫得非常棒丘喻,不但可以應(yīng)用在微信小程序云開發(fā)中泉粉,也可以用于在H5、app跺撼、微信服務(wù)號中實(shí)現(xiàn)微信支付功能讨彼,讓開發(fā)者不用每個(gè)人都自己造一遍車輪子了。

五哩至、使用node-tenpay實(shí)現(xiàn)微信支付功能

下面就說一下node-tenpay的使用:

1.node.js的安裝和使用

使用任何一個(gè)node.js模塊蜜自,都要先安裝node.js系統(tǒng)。在云函數(shù)中使用tenpay箭阶,就要在開發(fā)微信小程序的電腦上要安裝node.js系統(tǒng)。tenpay與云函數(shù)最終運(yùn)行在微信后臺的node.js環(huán)境下嘹叫,開發(fā)者要上傳云函數(shù)和tenpay相關(guān)依賴冈敛,而且相關(guān)依賴也要安裝在開發(fā)者本地抓谴。

image.png

node.js有適合各種操作系統(tǒng)的,下載安裝非常方便仰泻,但一開始用有點(diǎn)別扭滩届。node.js沒有圖形化的操作界面,所有操作都是依靠命令行的指令運(yùn)行相關(guān)程序棠枉,其中npm(node打包管理)程序的基本使用方法需要掌握泡挺。因?yàn)橄胍褂萌魏我粋€(gè)node.js模塊娄猫,都需要運(yùn)行npm指令安裝到本地電腦指定目錄才行。但這里不多說了月幌。

2.微信小程序云開發(fā)項(xiàng)目

在微信小程序新建項(xiàng)目的時(shí)候選擇小程序云開發(fā)悬蔽,然后創(chuàng)建一個(gè)云函數(shù),比如叫payment缅帘,在IDE環(huán)境下右鍵點(diǎn)擊payment文件夾难衰,在終端下打開,出現(xiàn)命令行窗口失暂,運(yùn)行:npm install tenpay,tenpay就安裝在了這個(gè)目錄下凭峡,用資源管理器可以看到payment文件夾下多了一個(gè)node_modules文件夾决记,微信小程序IDE一般會隱藏這個(gè)文件夾系宫,文件資源管理器可以看到,tenpay及其依賴的全部模塊就在這里扩借,npm還會生成一個(gè)package-lock.json文件潮罪,描述全部依賴關(guān)系,微信小程序IDE可以看到package-lock.json沃暗,這個(gè)會上傳到目標(biāo)環(huán)境何恶,在目標(biāo)環(huán)境下安裝依賴關(guān)系。

image

3.云函數(shù)代碼index.js:

//云函數(shù)實(shí)現(xiàn)微信支付
const cloud = require('wx-server-sdk')
cloud.init({
  env: 'shedeshushuXXXXXX'
})

// 步驟1、引入tenpay微信支付
const tenpay = require('tenpay');

// 步驟2今艺、配置支付信息
const config = {
  appid: 'wx349b000d8703a000',
  mchid: '1487305888',
  partnerKey: 'aaaaIIIIgggg11112222333344445555',     //就是微信支付賬戶里面設(shè)置的API密鑰
  pfx: require('fs').readFileSync('apiclient_cert.p12'),      //這是pfx格式的證書虚缎,支付不用證書钓株,但是退款什么的會用到
  notify_url: 'http://www.weixin.qq.com/wxpay/pay.php', //隨便寫一個(gè),云函數(shù)無法實(shí)現(xiàn)返回結(jié)果创坞,但有巧妙的方法實(shí)現(xiàn)同樣功能
  spbill_create_ip: '127.0.0.1'   //隨便寫一個(gè)受葛,為一些POS場合用的
};

// 云函數(shù)入口函數(shù)
exports.main = async(event, context) => {
  const wxContext = cloud.getWXContext()

  //步驟3,初始化支付
  const api = tenpay.init(config);

  //步驟4纲堵,調(diào)用席函,想用一個(gè)云函數(shù)實(shí)現(xiàn)全部支付功能,包括支付正蛙、退款何之、查詢等
  switch (event.command) {
    case "pay":  //支付功能
      return await api.getPayParams({
        out_trade_no: event.out_trade_no,   //這是商戶的訂單號,要求商戶內(nèi)唯一
        body: event.body,
        total_fee: event.total_fee,       //訂單金額(單位是分),
        openid: wxContext.OPENID   //付款用戶的openid徊件,直接拿就行
      })
      break

    case "payOK":    //想利用微信小程序得到付款成功消息后蒜危,給云函數(shù)來一個(gè)通知辐赞,解決付結(jié)果返回沒有服務(wù)器的問題
      console.log("en payOK, I known:", event.out_trade_no);
      break

    case "refund":    //退款功能
      console.log("refund, event, wxContext.OPENID", event, wxContext.OPENID);
      return await api.refund({
        // transaction_id, out_trade_no 二選一
        // transaction_id: '微信的訂單號',
        out_trade_no: event.out_trade_no,    //商戶訂單號
        out_refund_no: event.out_trade_no + 're',  //商戶退款訂單號,要求商戶內(nèi)唯一
        total_fee: event.total_fee,  //原單訂單金額(單位是分)
        refund_fee: event.refund_fee,
        refund_desc: event.refund_desc
      })
      // 相關(guān)默認(rèn)值:
      // op_user_id - 默認(rèn)為商戶號(此字段在小程序支付文檔中出現(xiàn))
      // notify_url - 默認(rèn)為初始化時(shí)傳入的refund_url, 無此參數(shù)則使用商戶后臺配置的退款通知地址
      break
  }
}

4.小程序端的代碼片段

  //提交訂單
  confirmOrder: function() {
    let that = this;
    wx.cloud.callFunction({
      name: "payment",
      data: {
        command: "pay",
        out_trade_no: "test0005",
        body: 'a7r2相機(jī)租賃',
        total_fee: 100
      },
      success(res) {
        console.log("云函數(shù)payment提交成功:", res.result)
        that.pay(res.result)
      },
      fail(res) {
        console.log("云函數(shù)payment提交失斝滤肌:", res)
      }
    })
  },

  //實(shí)現(xiàn)小程序支付
  pay(payData) {
    //官方標(biāo)準(zhǔn)的支付方法
    wx.requestPayment({ //已經(jīng)得到了5個(gè)參數(shù)
      timeStamp: payData.timeStamp,
      nonceStr: payData.nonceStr,
      package: payData.package, //統(tǒng)一下單接口返回的 prepay_id 格式如:prepay_id=***
      signType: 'MD5',
      paySign: payData.paySign, //簽名

      success(res) {
        console.log("支付成功:", res)
        wx.cloud.callFunction({  //巧妙利用小程序支付成功后的回調(diào)鲜漩,再次調(diào)用云函數(shù),通知其支付成功吝梅,以便進(jìn)行訂單狀態(tài)變更
          name: "payment",
          data: {
            command: "payOK",
            out_trade_no: "test0004"
          },
        })
      },
      fail(res) {
        console.log("支付失敺峤椤:", res)
      },
     complete(res) {
        console.log("支付完成:", res)
      }
    })
  },

  //退款
  refund: function() {
    let that = this;
    wx.cloud.callFunction({
      name: "payment",
      data: {
        command: "refund",
        out_trade_no: "test0005",
        body: 'a7r2相機(jī)租賃',
        total_fee: 1,
        refund_fee: 1,
        refund_desc: '押金退款'
      },
      success(res) {
        console.log("云函數(shù)payment提交成功:", res)
      },
      fail(res) {
        console.log("云函數(shù)payment提交失斄涌场:", res)
      }
    })
  }

5.利用小程序端支付成功回調(diào)云函數(shù)扇救,取向想商戶系統(tǒng)推送支付結(jié)果

小程序在調(diào)用 wx.requestPayment()發(fā)起支付后赊淑,如果支付成功陶缺,在回調(diào)函數(shù)中可以再次調(diào)用云函數(shù)洁灵,通知云函數(shù)支付成,以此取代向商戶系統(tǒng)服務(wù)推送支付結(jié)果苫费。這樣可以在不架設(shè)服務(wù)器的情況双抽,實(shí)現(xiàn)微信支付的全部功能。

6.實(shí)現(xiàn)退款功能必須要有證書

按照支付功能類似的方法做退款申請铐维,卻反復(fù)失敗報(bào)錯(cuò)慎菲!實(shí)際上露该,tenpay作者其實(shí)已經(jīng)在readme中講清楚了:
config說明:
pfx - 證書文件(選填, 在微信商戶管理界面獲取)
當(dāng)不需要調(diào)用依賴證書的API時(shí)可不填此參數(shù)
若業(yè)務(wù)流程中使用了依賴證書的API則需要在初始化時(shí)傳入此參數(shù)

微信支付平臺獲取證書,這里就不細(xì)說了抑党,按照官方說明一步一步做即可撵摆,生成的zip文件一定要保存好。這個(gè)zip文件中有3個(gè)文件,微信支付使用的是pfx苟呐,下圖中后綴為.p12的這個(gè)文件就是俐筋,將這個(gè)文件放在云函數(shù)payment的文件內(nèi),會與云函數(shù)其他文件一起上傳到運(yùn)行環(huán)境笆呆,退款申請就成功了。注意證書是由時(shí)效性的俄精,好像是1年榕堰,到期需要重新配置逆屡。

image
image
image

7.在一個(gè)云函數(shù)中實(shí)現(xiàn)全部微信支付API調(diào)用

除了支付功能外魏蔗,微信支付還有退款莺治、查詢訂單、查詢退款等多個(gè)功能产雹,這些功能可以集中在一個(gè)云函數(shù)中全部實(shí)現(xiàn)蔓挖。通過command參數(shù)區(qū)分需要調(diào)用哪個(gè)功能,微信小程序和云函數(shù)都可以調(diào)用這個(gè)微信支付云函數(shù)怨绣。具體代碼等舍得叔叔完善后在貼出吧拷获!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末匆瓜,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子茧妒,更是在濱河造成了極大的恐慌左冬,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,406評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件梅忌,死亡現(xiàn)場離奇詭異牧氮,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)展姐,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評論 3 393
  • 文/潘曉璐 我一進(jìn)店門圾笨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來逊谋,“玉大人,你說我怎么就攤上這事板鬓【啃簦” “怎么了?”我有些...
    開封第一講書人閱讀 163,711評論 0 353
  • 文/不壞的土叔 我叫張陵抄腔,是天一觀的道長理张。 經(jīng)常有香客問我,道長悟耘,這世上最難降的妖魔是什么织狐? 我笑而不...
    開封第一講書人閱讀 58,380評論 1 293
  • 正文 為了忘掉前任移迫,我火速辦了婚禮,結(jié)果婚禮上鹰服,老公的妹妹穿的比我還像新娘揽咕。我一直安慰自己,他們只是感情好设易,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,432評論 6 392
  • 文/花漫 我一把揭開白布顿肺。 她就那樣靜靜地躺著渣蜗,像睡著了一般。 火紅的嫁衣襯著肌膚如雪讼昆。 梳的紋絲不亂的頭發(fā)上骚烧,一...
    開封第一講書人閱讀 51,301評論 1 301
  • 那天赃绊,我揣著相機(jī)與錄音,去河邊找鬼运敢。 笑死么夫,一個(gè)胖子當(dāng)著我的面吹牛档痪,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播愿汰,決...
    沈念sama閱讀 40,145評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼乐纸,長吁一口氣:“原來是場噩夢啊……” “哼汽绢!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起跌宛,我...
    開封第一講書人閱讀 39,008評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蜕猫,沒想到半個(gè)月后哎迄,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體漱挚,經(jīng)...
    沈念sama閱讀 45,443評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡旨涝,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,649評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了哩治。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,795評論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡衬鱼,死狀恐怖业筏,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情鸟赫,我是刑警寧澤蒜胖,帶...
    沈念sama閱讀 35,501評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站抛蚤,受9級特大地震影響台谢,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜岁经,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,119評論 3 328
  • 文/蒙蒙 一朋沮、第九天 我趴在偏房一處隱蔽的房頂上張望缀壤。 院中可真熱鬧樊拓,春花似錦、人聲如沸塘慕。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽图呢。三九已至条篷,卻和暖如春骗随,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背赴叹。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評論 1 269
  • 我被黑心中介騙來泰國打工蚊锹, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人稚瘾。 一個(gè)月前我還...
    沈念sama閱讀 47,899評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像姚炕,于是被迫代替她去往敵國和親摊欠。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,724評論 2 354

推薦閱讀更多精彩內(nèi)容