${body}<\/body>\r\n?${mch_id}<\/mch_id>\r\n?${nonce_str}<\/nonce_str>\r\n?${notify_url}<\/notify_url>\r\n?${nonce_str}<\/out_trade_no>\r\n?${fee}<\/total_fee>\r\n?${server_ip}<\/spbill_create_ip>\r\n?NATIVE<\/trade_type>\r\n?${signString(fee,?server_ip,?nonce_str)}<\/sign>\r\n?<\/xml>\r\n?`\r\n?return?{\r\n?xml,\r\n?out_trade_no:?nonce_str\r\n?}\r\n}<\/pre>\n

如果你怕自己的簽名的 xml<\/code> 串有問題,可以提前在微信提供的簽名校驗(yàn)工具里先校驗(yàn)一遍,看看是否能通過。<\/p>\n

發(fā)送請(qǐng)求<\/strong><\/span><\/p>\n

因?yàn)樾枰⑿欧?wù)端發(fā)請(qǐng)求,所以我選擇了 axios<\/code> 這個(gè)在瀏覽器端和node端都能發(fā)起ajax請(qǐng)求的庫。<\/p>\n

安裝過程不再贅述。繼續(xù)在 wechatpay.js<\/code> 寫發(fā)請(qǐng)求的邏輯。<\/p>\n

由于微信給我們返回的也將是一個(gè)xml格式的字符串。所以我們需要預(yù)先寫好解析函數(shù),將xml解析成js對(duì)象。為此你可以安裝一個(gè) xml2js 。安裝過程跟上面的類似,不再贅述。<\/p>\n

微信會(huì)給我們返回一個(gè)諸如下面格式的 xml<\/code> 字符串:<\/p>\n

<\/return_code>\r\n<\/return_msg>\r\n<\/appid>\r\n<\/mch_id>\r\n<\/nonce_str>\r\n<\/sign>\r\n<\/result_code>\r\n<\/prepay_id>\r\n<\/trade_type>\r\n<\/code_url>\r\n<\/xml><\/pre>\n

我們的目標(biāo)是轉(zhuǎn)為如下的js對(duì)象,好讓我們用js來操作數(shù)據(jù):<\/p>\n

{\r\n?return_code:?'SUCCESS',?\/\/?SUCCESS?或者?FAIL\r\n?return_msg:?'OK',\r\n?appid:?'wx742xxxxxxxxxxxxx',\r\n?mch_id:?'14899xxxxx',\r\n?nonce_str:?'R69QXXXXXXXX6O',\r\n?sign:?'79F0891XXXXXX189507A184XXXXXXXXX',\r\n?result_code:?'SUCCESS',\r\n?prepay_id:?'wx152316xxxxxxxxxxxxxxxxxxxxxxxxxxx',\r\n?trade_type:?'NATIVE',\r\n?code_url:?'weixin:\/\/wxpay\/xxxurl?pr=dQNakHH'?\/\/?用于生成支付二維碼的鏈接\r\n}<\/pre>\n

于是我們寫一個(gè)函數(shù),調(diào)用 xml2js<\/code> 來解析xml:<\/p>\n

\/\/?將XML轉(zhuǎn)為JS對(duì)象\r\nconst?parseXML?=?(xml)?=>?{\r\n?return?new?Promise((res,?rej)?=>?{\r\n?xml2js.parseString(xml,?{trim:?true,?explicitArray:?false},?(err,?json)?=>?{\r\n?if?(err)?{\r\n?rej(err)\r\n?}?else?{\r\n?res(json.xml)\r\n?}\r\n?})\r\n?})\r\n}<\/pre>\n

上面的代碼返回了一個(gè) Promise<\/code> 對(duì)象,因?yàn)?xml2js<\/code> 的操作是在回調(diào)函數(shù)<\/a>里返回的結(jié)果,所以為了配合Koa2的 async<\/code> 、 await<\/code> ,我們可以將其封裝成一個(gè) Promise<\/code> 對(duì)象,將解析完的結(jié)果通過 resolve<\/code> 返回回去。這樣就能用 await<\/code> 來取數(shù)據(jù)了:<\/p>\n

const?axios?=?require('axios')\r\nconst?url?=?'https:\/\/api.mch.weixin.qq.com\/pay\/unifiedorder'?\/\/?微信服務(wù)端地址\r\nconst?pay?=?async?(ctx)?=>?{\r\n?const?form?=?ctx.request.body?\/\/?通過前端傳來的數(shù)據(jù)\r\n?const?orderNo?=?'XXXXXXXXXXXXXXXX'?\/\/?不重復(fù)的訂單號(hào)\r\n?const?fee?=?form.fee?\/\/?通過前端傳來的費(fèi)用值\r\n?const?data?=?xmlBody(fee,?orderNo)?\/\/?fee是費(fèi)用,orderNo是訂單號(hào)(唯一)\r\n?const?res?=?await?axios.post(url,?{\r\n?data:?data.xml\r\n?}).then(async?res?=>?{\r\n?const?resJson?=?await?parseXML(res.data)\r\n?return?resJson?\/\/?拿到返回的數(shù)據(jù)\r\n?}).catch(err?=>?{\r\n?console.log(err)\r\n?})\r\n?if?(res.return_code?===?'SUCCESS')?{?\/\/?如果返回的\r\n?return?ctx.body?=?{\r\n?success:?true,\r\n?message:?'請(qǐng)求成功',\r\n?code_url:?res.code_url,?\/\/?code_url就是用于生成支付二維碼的鏈接\r\n?order_no:?orderNo?\/\/?訂單號(hào)\r\n?}\r\n?}\r\n?ctx.body?=?{\r\n?success:?false,\r\n?message:?'請(qǐng)求失敗'\r\n?}\r\n}\r\nrouter.post('\/api\/pay',?pay)\r\nmodule.exports?=?router<\/pre>\n

然后我們要將這個(gè)router掛載到根目錄的 app.js<\/code> 里去。<\/p>\n

找到之前默認(rèn)的兩個(gè)路由,一個(gè) index<\/code> ,一個(gè) user<\/code> :<\/p>\n

const?index?=?require('.\/routes\/index')\r\nconst?users?=?require('.\/routes\/users')\r\nconst?wechatpay?=?require('.\/routes\/wechatpay')?\/\/?加在這里<\/pre>\n

然后到頁面底下掛載這個(gè)路由:<\/p>\n

\/\/?routes\r\napp.use(index.routes(),?index.allowedMethods())\r\napp.use(users.routes(),?users.allowedMethods())\r\napp.use(wechatpay.routes(),?users.allowedMethods())?\/\/?加在這里<\/pre>\n

于是你就可以通過發(fā)送 \/api\/pay<\/code> 來請(qǐng)求二維碼數(shù)據(jù)啦。(如果有跨域需要自己考慮解決跨域方案,可以跟Koa放在同域里,也可以開一層proxy來轉(zhuǎn)發(fā),也可以開CORS頭等等)<\/p>\n

注意, 本例里是用前端來生成二維碼,其實(shí)也可以通過后端生成二維碼,然后再返回給前端。不過為了簡(jiǎn)易演示,本例采用前端通過獲取 code_url<\/code> 后,在前端生成二維碼。<\/p>\n

展示支付二維碼<\/strong><\/span><\/p>\n

前端我用的是 Vue<\/code> ,當(dāng)然你可以選擇你喜歡的前端框架。這里關(guān)注點(diǎn)在于通過拿到剛才后端傳過來的 code_url<\/code> 來生成二維碼。<\/p>\n

在前端,我使用的是 @xkeshi\/vue-qrcode 這個(gè)庫來生成二維碼。它調(diào)用特別簡(jiǎn)單:<\/p>\n

import?VueQrcode?from?'@xkeshi\/vue-qrcode'\r\nexport?default?{\r\n?components:?{\r\n?VueQrcode\r\n?},\r\n?\/\/?...其他代碼\r\n}<\/pre>\n

然后就可以在前端里用 <\/code> 的組件來生成二維碼了:<\/p>\n

<\/pre>\n

放到Dialog里就是這樣的效果:<\/p>\n

文本是我自己添加的<\/p>\n

\"\"?<\/p>\n

付款成功自動(dòng)刷新頁面<\/strong><\/span><\/p>\n

有兩種將支付成功寫入數(shù)據(jù)庫的辦法。<\/p>\n

一種是在打開了掃碼對(duì)話框后,不停向微信服務(wù)端輪詢支付結(jié)果,如果支付成功,那么就向后端發(fā)起請(qǐng)求,告訴后端支付成功,讓后端寫入數(shù)據(jù)庫。<\/p>\n

一種是后端一直開著接口,等微信主動(dòng)給后端的 notify_url<\/code> 發(fā)起post請(qǐng)求,告訴后端支付結(jié)果,讓后端寫入數(shù)據(jù)庫。然后此時(shí)前端向后端輪詢的時(shí)候應(yīng)該是去數(shù)據(jù)庫取輪詢?cè)撚唵蔚闹Ц督Y(jié)果,如果支付成功就關(guān)閉Dialog。<\/p>\n

第一種比較簡(jiǎn)單但是不安全:試想萬一用戶支付成功的同時(shí)關(guān)閉了頁面,或者用戶支付成功了,但是網(wǎng)絡(luò)有問題導(dǎo)致前端沒法往后端發(fā)支付成功的結(jié)果,那么后端就一直沒辦法寫入支付成功的數(shù)據(jù)。<\/p>\n

第二種雖然麻煩,但是保證了安全。所有的支付結(jié)果都必須等微信主動(dòng)向后端通知,后端存完數(shù)據(jù)庫后再返回給前端消息。這樣哪怕用戶支付成功的同時(shí)關(guān)閉了頁面,下次再打開的時(shí)候,由于數(shù)據(jù)庫已經(jīng)寫入了,所以拿到的也是支付成功的結(jié)果。<\/p>\n

所以 付款成功自動(dòng)刷新頁面<\/code> 這個(gè)部分我們分為兩個(gè)部分來說:<\/p>\n

前端部分<\/strong><\/span><\/p>\n

Vue的data部分<\/p>\n

data:?{\r\n?payStatus:?false,?\/\/?未支付成功\r\n?retryCount:?0,?\/\/?輪詢次數(shù),從0-200\r\n?orderNo:?'xxx',?\/\/?從后端傳來的order_no\r\n?codeUrl:?'xxx'?\/\/?從后端傳來的code_url\r\n}<\/pre>\n

在methods里寫一個(gè)查詢訂單信息的方法:<\/p>\n

\/\/?...\r\nhandleCheckBill?()?{\r\n?return?setTimeout(()?=>?{\r\n?if?(!this.payStatus?&&?this.retryCount?< 120) {\r\n this.retryCount += 1\r\n axios.post('\/api\/check-bill', { \/\/ 向后端請(qǐng)求訂單支付信息\r\n orderNo: this.orderNo\r\n })\r\n .then(res =>?{\r\n?if?(res.data.success)?{\r\n?this.payStatus?=?true\r\n?location.reload()?\/\/?偷懶就用reload重新刷新頁面\r\n?}?else?{\r\n?this.handleCheckBill()\r\n?}\r\n?}).catch(err?=>?{\r\n?console.log(err)\r\n?})\r\n?}?else?{\r\n?location.reload()\r\n?}\r\n?},?1000)\r\n}<\/pre>\n

在打開二維碼Dialog的時(shí)候,這個(gè)方法就啟用了。然后就開始輪詢。我訂了一個(gè)時(shí)間,200s后如果還是沒有付款信息也自動(dòng)刷新頁面。實(shí)際上你可以自己根據(jù)項(xiàng)目的需要來定義這個(gè)時(shí)間。<\/p>\n

后端部分<\/strong><\/span><\/p>\n

前端到后端只有一個(gè)接口,但是后端有兩個(gè)接口。一個(gè)是用來接收微信的推送,一個(gè)是用來接收前端的查詢請(qǐng)求。<\/p>\n

先來寫最關(guān)鍵的微信的推送請(qǐng)求處理。由于我們接收微信的請(qǐng)求是在Koa的路由里,并且是以流的形式傳輸?shù)?。需要讓Koa支持解析xml格式的body,所以需要安裝一個(gè)rawbody 來獲取xml格式的body。<\/p>\n

\/\/?處理微信支付回傳notify\r\n\/\/?如果收到消息要跟微信回傳是否接收到\r\nconst?handleNotify?=?async?(ctx)?=>?{\r\n?const?xml?=?await?rawbody(ctx.req,?{\r\n?length:?ctx.request.length,\r\n?limit:?'1mb',\r\n?encoding:?ctx.request.charset?||?'utf-8'\r\n?})\r\n?const?res?=?await?parseXML(xml)?\/\/?解析xml\r\n?if?(res.return_code?===?'SUCCESS')?{\r\n?if?(res.result_code?===?'SUCCESS')?{?\/\/?如果都為SUCCESS代表支付成功\r\n?\/\/?...?這里是寫入數(shù)據(jù)庫的相關(guān)操作\r\n?\/\/?開始回傳微信\r\n?ctx.type?=?'application\/xml'?\/\/?指定發(fā)送的請(qǐng)求類型是xml\r\n?\/\/?回傳微信,告訴已經(jīng)收到\r\n?return?ctx.body?=?`\r\n?<\/return_code>\r\n?<\/return_msg>\r\n?<\/xml>\r\n?`\r\n?}\r\n?}\r\n?\/\/?如果支付失敗,也回傳微信\r\n?ctx.status?=?400\r\n?ctx.type?=?'application\/xml'\r\n?ctx.body?=?`\r\n?<\/return_code>\r\n?<\/return_msg>\r\n?<\/xml>\r\n?`\r\n}\r\nrouter.post('\/api\/notify',?handleNotify)<\/pre>\n

這里的坑就是Koa處理微信回傳的xml。如果不知道是以 raw-body<\/code> 的形式回傳的,會(huì)調(diào)試半天。。<\/p>\n

接下來這個(gè)就是比較簡(jiǎn)單的給前端回傳的了。<\/p>\n

const?checkBill?=?async?(ctx)?=>?{\r\n?const?form?=?ctx.request.body\r\n?const?orderNo?=?form.orderNo\r\n?const?result?=?await?數(shù)據(jù)庫操作\r\n?if?(result)?{?\/\/?如果訂單支付成功\r\n?return?ctx.body?=?{\r\n?success:?true\r\n?}\r\n?}\r\n?ctx.status?=?400\r\n?ctx.body?=?{\r\n?success:?false\r\n?}\r\n}\r\nrouter.post('\/api\/check-bill',?checkBill)<\/pre>\n

相信看了本文案例你已經(jīng)掌握了方法,更多精彩請(qǐng)關(guān)注php中文網(wǎng)其它相關(guān)文章!<\/p>\n

推薦閱讀:<\/p>\n

如何操作Koa2微信公眾號(hào)開發(fā)之本地開發(fā)調(diào)試環(huán)境搭建<\/a>
<\/p>\n

如何操作Koa2微信公眾號(hào)實(shí)現(xiàn)消息管理<\/a>
<\/p>"}

国产av日韩一区二区三区精品,成人性爱视频在线观看,国产,欧美,日韩,一区,www.成色av久久成人,2222eeee成人天堂

Home WeChat Applet WeChat Development How to use Koa2 to develop WeChat QR code scanning payment

How to use Koa2 to develop WeChat QR code scanning payment

May 29, 2018 am 11:23 AM
koa2 develop

This time I will show you how to use Koa2 to develop WeChat QR code scanning payment, and what are the precautions of using Koa2 to develop WeChat QR code scanning payment. The following is a practical case, let's come together take a look.

I was developing a function some time ago, and the requirement is to pay by scanning the WeChat QR code. This scenario is not uncommon for us. Various electronic shopping malls, offline vending machines, etc. all have this function. Usually I am just a user, but now I am a developer, which is not a small pitfall. So hereby write a blog to record it.

Note: To develop WeChat QR code payment, you must have the permission of the corresponding merchant account, otherwise you will not be able to develop it. If you do not have the corresponding permissions, this article is not recommended to be read.

Two modes

Open the WeChat payment document, we can see two payment modes: mode one and mode two. The flow charts of both are given in the WeChat documentation (but to be honest, the drawings are really ugly).

The document points out the difference between the two:

Before the development of Mode 1, merchants must set a payment callback URL in the backend of the public platform. Function implemented by URL: Receive the productid and openid called back by the WeChat payment system after the user scans the QR code.

Compared with Mode 1, Mode 2 has a simpler process and does not rely on the set callback payment URL. The merchant's backend system first calls the unified ordering interface of WeChat payment. The WeChat backend system returns the link parameter code_url. The merchant's backend system generates a QR code image from the code_url value. The user uses the WeChat client to scan the code and initiate payment. Note: code_url is valid for 2 hours. After expiration, scanning the code cannot initiate payment.

Mode 1 is more common when we shop online. A special page will pop up for scanning the QR code to pay. Then after the payment is successful, this page will jump back to the callback page again to notify you that the payment was successful. The second one is less likely to be correct, but the second one is relatively simple to develop.

This article mainly introduces the development of mode two.

Build a simple development environment for Koa2

I recommend using koa-generator to quickly build a development environment for Koa2. Scaffolding can help us save some basic middleware writing steps at the beginning of the Koa project. (If you want to learn Koa, it’s best to build one yourself. If you already know Koa, you can use some quick scaffolding.)

First install it globally

koa-generator:

npm?install?-g?koa-generator
#or
yarn?global?add?koa-generator
Then find a directory to store the Koa project. We plan to name this project

koa-wechatpay, and then enter koa2 koa-wechatpay. Then the scaffolding will automatically create the corresponding folder koa-wechatpay and generate the basic skeleton. Go into this folder and install the corresponding plug-in. Enter:

npm?install
#or
yarn
Then you can enter

npm start or yarn start to run the project (the default listening port is 3000).

If nothing else happens, your project is running, and then we use postman to test it:

This route is in

routes/index.js.

If you see

{
?"title":?"koa2?json"
}
, it means there is no problem. (If there is a problem, check whether the port is occupied, etc.)

Next, we create a new file

wechatpay.js in the routes folder Used to write our processes.

Signature

#The key to communicating with the WeChat server is that the signature must be correct. If the signature is incorrect, then everything is in vain.

First we need to go to the backend of the official account to obtain the following corresponding id or key information we need. Among them,

notify_url and server_ip are used for when our payment is successful, WeChat will actively send the payment success information to this url post.

The signature algorithm is as follows:

https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=4_3

In order for the signature to be correct , we need to install

md5.

npm?install?md5?--save
#or
yarn?add?md5
const?md5?=?require('md5')
const?appid?=?'xxx'
const?mch_id?=?'yyy'
const?mch_api_key?=?'zzz'
const?notify_url?=?'http://xxx/api/notify'?//?服務(wù)端可訪問的域名和接口
const?server_ip?=?'xx.xx.xx.xx'?//?服務(wù)端的ip地址
const?trade_type?=?'NATIVE'?//?NATIVE對(duì)應(yīng)的是二維碼掃碼支付
let?body?=?'XXX的充值支付'?//?用于顯示在支付界面的提示詞
Then start writing the signature function:

const?signString?=?(fee,?ip,?nonce)?=>?{
?let?tempString?=?`appid=${appid}&body=${body}&mch_id=${mch_id}&nonce_str=${nonce}&notify_url=${notify_url}&out_trade_no=${nonce}&spbill_create_ip=${ip}&total_fee=${fee}&trade_type=${trade_type}&key=${mch_api_key}`
?return?md5(tempString).toUpperCase()
}

其中 fee 是要充值的費(fèi)用,以分為單位。比如要充值1塊錢, fee 就是100。ip是個(gè)比較隨意的選項(xiàng),只要符合規(guī)則的ip經(jīng)過測(cè)試都是可以的,下文里我用的是 server_ip 。 nonce 就是微信要求的不重復(fù)的32位以內(nèi)的字符串,通??梢允褂糜唵翁?hào)等唯一標(biāo)識(shí)的字符串。

由于跟微信的服務(wù)器交流都是用xml來交流,所以現(xiàn)在我們要手動(dòng)組裝一下post請(qǐng)求xml :

const?xmlBody?=?(fee,?nonce_str)?=>?{
?const?xml?=?`
?<xml>
?<appid>${appid}</appid>
?<body>${body}</body>
?<mch_id>${mch_id}</mch_id>
?<nonce_str>${nonce_str}</nonce_str>
?<notify_url>${notify_url}</notify_url>
?<out_trade_no>${nonce_str}</out_trade_no>
?<total_fee>${fee}</total_fee>
?<spbill_create_ip>${server_ip}</spbill_create_ip>
?<trade_type>NATIVE</trade_type>
?<sign>${signString(fee,?server_ip,?nonce_str)}</sign>
?</xml>
?`
?return?{
?xml,
?out_trade_no:?nonce_str
?}
}

如果你怕自己的簽名的 xml 串有問題,可以提前在微信提供的簽名校驗(yàn)工具里先校驗(yàn)一遍,看看是否能通過。

發(fā)送請(qǐng)求

因?yàn)樾枰⑿欧?wù)端發(fā)請(qǐng)求,所以我選擇了 axios 這個(gè)在瀏覽器端和node端都能發(fā)起ajax請(qǐng)求的庫。

安裝過程不再贅述。繼續(xù)在 wechatpay.js 寫發(fā)請(qǐng)求的邏輯。

由于微信給我們返回的也將是一個(gè)xml格式的字符串。所以我們需要預(yù)先寫好解析函數(shù),將xml解析成js對(duì)象。為此你可以安裝一個(gè) xml2js 。安裝過程跟上面的類似,不再贅述。

微信會(huì)給我們返回一個(gè)諸如下面格式的 xml 字符串:

<xml><return_code><![CDATA[SUCCESS]]></return_code>
<return_msg><![CDATA[OK]]></return_msg>
<appid><![CDATA[wx742xxxxxxxxxxxxx]]></appid>
<mch_id><![CDATA[14899xxxxx]]></mch_id>
<nonce_str><![CDATA[R69QXXXXXXXX6O]]></nonce_str>
<sign><![CDATA[79F0891XXXXXX189507A184XXXXXXXXX]]></sign>
<result_code><![CDATA[SUCCESS]]></result_code>
<prepay_id><![CDATA[wx152316xxxxxxxxxxxxxxxxxxxxxxxxxxx]]></prepay_id>
<trade_type><![CDATA[NATIVE]]></trade_type>
<code_url><![CDATA[weixin://wxpay/xxxurl?pr=dQNakHH]]></code_url>
</xml>

我們的目標(biāo)是轉(zhuǎn)為如下的js對(duì)象,好讓我們用js來操作數(shù)據(jù):

{
?return_code:?'SUCCESS',?//?SUCCESS?或者?FAIL
?return_msg:?'OK',
?appid:?'wx742xxxxxxxxxxxxx',
?mch_id:?'14899xxxxx',
?nonce_str:?'R69QXXXXXXXX6O',
?sign:?'79F0891XXXXXX189507A184XXXXXXXXX',
?result_code:?'SUCCESS',
?prepay_id:?'wx152316xxxxxxxxxxxxxxxxxxxxxxxxxxx',
?trade_type:?'NATIVE',
?code_url:?'weixin://wxpay/xxxurl?pr=dQNakHH'?//?用于生成支付二維碼的鏈接
}

于是我們寫一個(gè)函數(shù),調(diào)用 xml2js 來解析xml:

//?將XML轉(zhuǎn)為JS對(duì)象
const?parseXML?=?(xml)?=>?{
?return?new?Promise((res,?rej)?=>?{
?xml2js.parseString(xml,?{trim:?true,?explicitArray:?false},?(err,?json)?=>?{
?if?(err)?{
?rej(err)
?}?else?{
?res(json.xml)
?}
?})
?})
}

上面的代碼返回了一個(gè) Promise 對(duì)象,因?yàn)?xml2js 的操作是在回調(diào)函數(shù)里返回的結(jié)果,所以為了配合Koa2的 async 、 await ,我們可以將其封裝成一個(gè) Promise 對(duì)象,將解析完的結(jié)果通過 resolve 返回回去。這樣就能用 await 來取數(shù)據(jù)了:

const?axios?=?require('axios')
const?url?=?'https://api.mch.weixin.qq.com/pay/unifiedorder'?//?微信服務(wù)端地址
const?pay?=?async?(ctx)?=>?{
?const?form?=?ctx.request.body?//?通過前端傳來的數(shù)據(jù)
?const?orderNo?=?'XXXXXXXXXXXXXXXX'?//?不重復(fù)的訂單號(hào)
?const?fee?=?form.fee?//?通過前端傳來的費(fèi)用值
?const?data?=?xmlBody(fee,?orderNo)?//?fee是費(fèi)用,orderNo是訂單號(hào)(唯一)
?const?res?=?await?axios.post(url,?{
?data:?data.xml
?}).then(async?res?=>?{
?const?resJson?=?await?parseXML(res.data)
?return?resJson?//?拿到返回的數(shù)據(jù)
?}).catch(err?=>?{
?console.log(err)
?})
?if?(res.return_code?===?'SUCCESS')?{?//?如果返回的
?return?ctx.body?=?{
?success:?true,
?message:?'請(qǐng)求成功',
?code_url:?res.code_url,?//?code_url就是用于生成支付二維碼的鏈接
?order_no:?orderNo?//?訂單號(hào)
?}
?}
?ctx.body?=?{
?success:?false,
?message:?'請(qǐng)求失敗'
?}
}
router.post('/api/pay',?pay)
module.exports?=?router

然后我們要將這個(gè)router掛載到根目錄的 app.js 里去。

找到之前默認(rèn)的兩個(gè)路由,一個(gè) index ,一個(gè) user

const?index?=?require('./routes/index')
const?users?=?require('./routes/users')
const?wechatpay?=?require('./routes/wechatpay')?//?加在這里

然后到頁面底下掛載這個(gè)路由:

//?routes
app.use(index.routes(),?index.allowedMethods())
app.use(users.routes(),?users.allowedMethods())
app.use(wechatpay.routes(),?users.allowedMethods())?//?加在這里

于是你就可以通過發(fā)送 /api/pay 來請(qǐng)求二維碼數(shù)據(jù)啦。(如果有跨域需要自己考慮解決跨域方案,可以跟Koa放在同域里,也可以開一層proxy來轉(zhuǎn)發(fā),也可以開CORS頭等等)

注意, 本例里是用前端來生成二維碼,其實(shí)也可以通過后端生成二維碼,然后再返回給前端。不過為了簡(jiǎn)易演示,本例采用前端通過獲取 code_url 后,在前端生成二維碼。

展示支付二維碼

前端我用的是 Vue ,當(dāng)然你可以選擇你喜歡的前端框架。這里關(guān)注點(diǎn)在于通過拿到剛才后端傳過來的 code_url 來生成二維碼。

在前端,我使用的是 @xkeshi/vue-qrcode 這個(gè)庫來生成二維碼。它調(diào)用特別簡(jiǎn)單:

import?VueQrcode?from?'@xkeshi/vue-qrcode'
export?default?{
?components:?{
?VueQrcode
?},
?//?...其他代碼
}

然后就可以在前端里用 <vue-qrcode> 的組件來生成二維碼了:

<vue-qrcode :value="codeUrl" :options="{ size: 200 }">

放到Dialog里就是這樣的效果:

文本是我自己添加的

?

付款成功自動(dòng)刷新頁面

有兩種將支付成功寫入數(shù)據(jù)庫的辦法。

一種是在打開了掃碼對(duì)話框后,不停向微信服務(wù)端輪詢支付結(jié)果,如果支付成功,那么就向后端發(fā)起請(qǐng)求,告訴后端支付成功,讓后端寫入數(shù)據(jù)庫。

一種是后端一直開著接口,等微信主動(dòng)給后端的 notify_url 發(fā)起post請(qǐng)求,告訴后端支付結(jié)果,讓后端寫入數(shù)據(jù)庫。然后此時(shí)前端向后端輪詢的時(shí)候應(yīng)該是去數(shù)據(jù)庫取輪詢?cè)撚唵蔚闹Ц督Y(jié)果,如果支付成功就關(guān)閉Dialog。

第一種比較簡(jiǎn)單但是不安全:試想萬一用戶支付成功的同時(shí)關(guān)閉了頁面,或者用戶支付成功了,但是網(wǎng)絡(luò)有問題導(dǎo)致前端沒法往后端發(fā)支付成功的結(jié)果,那么后端就一直沒辦法寫入支付成功的數(shù)據(jù)。

第二種雖然麻煩,但是保證了安全。所有的支付結(jié)果都必須等微信主動(dòng)向后端通知,后端存完數(shù)據(jù)庫后再返回給前端消息。這樣哪怕用戶支付成功的同時(shí)關(guān)閉了頁面,下次再打開的時(shí)候,由于數(shù)據(jù)庫已經(jīng)寫入了,所以拿到的也是支付成功的結(jié)果。

所以 付款成功自動(dòng)刷新頁面 這個(gè)部分我們分為兩個(gè)部分來說:

前端部分

Vue的data部分

data:?{
?payStatus:?false,?//?未支付成功
?retryCount:?0,?//?輪詢次數(shù),從0-200
?orderNo:?'xxx',?//?從后端傳來的order_no
?codeUrl:?'xxx'?//?從后端傳來的code_url
}

在methods里寫一個(gè)查詢訂單信息的方法:

//?...
handleCheckBill?()?{
?return?setTimeout(()?=>?{
?if?(!this.payStatus?&&?this.retryCount?< 120) {
 this.retryCount += 1
 axios.post(&#39;/api/check-bill&#39;, { // 向后端請(qǐng)求訂單支付信息
 orderNo: this.orderNo
 })
 .then(res =>?{
?if?(res.data.success)?{
?this.payStatus?=?true
?location.reload()?//?偷懶就用reload重新刷新頁面
?}?else?{
?this.handleCheckBill()
?}
?}).catch(err?=>?{
?console.log(err)
?})
?}?else?{
?location.reload()
?}
?},?1000)
}

在打開二維碼Dialog的時(shí)候,這個(gè)方法就啟用了。然后就開始輪詢。我訂了一個(gè)時(shí)間,200s后如果還是沒有付款信息也自動(dòng)刷新頁面。實(shí)際上你可以自己根據(jù)項(xiàng)目的需要來定義這個(gè)時(shí)間。

后端部分

前端到后端只有一個(gè)接口,但是后端有兩個(gè)接口。一個(gè)是用來接收微信的推送,一個(gè)是用來接收前端的查詢請(qǐng)求。

先來寫最關(guān)鍵的微信的推送請(qǐng)求處理。由于我們接收微信的請(qǐng)求是在Koa的路由里,并且是以流的形式傳輸?shù)摹P枰孠oa支持解析xml格式的body,所以需要安裝一個(gè)rawbody 來獲取xml格式的body。

//?處理微信支付回傳notify
//?如果收到消息要跟微信回傳是否接收到
const?handleNotify?=?async?(ctx)?=>?{
?const?xml?=?await?rawbody(ctx.req,?{
?length:?ctx.request.length,
?limit:?'1mb',
?encoding:?ctx.request.charset?||?'utf-8'
?})
?const?res?=?await?parseXML(xml)?//?解析xml
?if?(res.return_code?===?'SUCCESS')?{
?if?(res.result_code?===?'SUCCESS')?{?//?如果都為SUCCESS代表支付成功
?//?...?這里是寫入數(shù)據(jù)庫的相關(guān)操作
?//?開始回傳微信
?ctx.type?=?'application/xml'?//?指定發(fā)送的請(qǐng)求類型是xml
?//?回傳微信,告訴已經(jīng)收到
?return?ctx.body?=?`<xml>
?<return_code><![CDATA[SUCCESS]]></return_code>
?<return_msg><![CDATA[OK]]></return_msg>
?</xml>
?`
?}
?}
?//?如果支付失敗,也回傳微信
?ctx.status?=?400
?ctx.type?=?'application/xml'
?ctx.body?=?`<xml>
?<return_code><![CDATA[FAIL]]></return_code>
?<return_msg><![CDATA[OK]]></return_msg>
?</xml>
?`
}
router.post('/api/notify',?handleNotify)

這里的坑就是Koa處理微信回傳的xml。如果不知道是以 raw-body 的形式回傳的,會(huì)調(diào)試半天。。

接下來這個(gè)就是比較簡(jiǎn)單的給前端回傳的了。

const?checkBill?=?async?(ctx)?=>?{
?const?form?=?ctx.request.body
?const?orderNo?=?form.orderNo
?const?result?=?await?數(shù)據(jù)庫操作
?if?(result)?{?//?如果訂單支付成功
?return?ctx.body?=?{
?success:?true
?}
?}
?ctx.status?=?400
?ctx.body?=?{
?success:?false
?}
}
router.post('/api/check-bill',?checkBill)

相信看了本文案例你已經(jīng)掌握了方法,更多精彩請(qǐng)關(guān)注php中文網(wǎng)其它相關(guān)文章!

推薦閱讀:

如何操作Koa2微信公眾號(hào)開發(fā)之本地開發(fā)調(diào)試環(huán)境搭建

如何操作Koa2微信公眾號(hào)實(shí)現(xiàn)消息管理

The above is the detailed content of How to use Koa2 to develop WeChat QR code scanning payment. For more information, please follow other related articles on the PHP Chinese website!

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undress AI Tool

Undress AI Tool

Undress images for free

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

Hot Topics

PHP Tutorial
1502
276
Four recommended AI-assisted programming tools Four recommended AI-assisted programming tools Apr 22, 2024 pm 05:34 PM

This AI-assisted programming tool has unearthed a large number of useful AI-assisted programming tools in this stage of rapid AI development. AI-assisted programming tools can improve development efficiency, improve code quality, and reduce bug rates. They are important assistants in the modern software development process. Today Dayao will share with you 4 AI-assisted programming tools (and all support C# language). I hope it will be helpful to everyone. https://github.com/YSGStudyHards/DotNetGuide1.GitHubCopilotGitHubCopilot is an AI coding assistant that helps you write code faster and with less effort, so you can focus more on problem solving and collaboration. Git

Which AI programmer is the best? Explore the potential of Devin, Tongyi Lingma and SWE-agent Which AI programmer is the best? Explore the potential of Devin, Tongyi Lingma and SWE-agent Apr 07, 2024 am 09:10 AM

On March 3, 2022, less than a month after the birth of the world's first AI programmer Devin, the NLP team of Princeton University developed an open source AI programmer SWE-agent. It leverages the GPT-4 model to automatically resolve issues in GitHub repositories. SWE-agent's performance on the SWE-bench test set is similar to Devin, taking an average of 93 seconds and solving 12.29% of the problems. By interacting with a dedicated terminal, SWE-agent can open and search file contents, use automatic syntax checking, edit specific lines, and write and execute tests. (Note: The above content is a slight adjustment of the original content, but the key information in the original text is retained and does not exceed the specified word limit.) SWE-A

Learn how to develop mobile applications using Go language Learn how to develop mobile applications using Go language Mar 28, 2024 pm 10:00 PM

Go language development mobile application tutorial As the mobile application market continues to boom, more and more developers are beginning to explore how to use Go language to develop mobile applications. As a simple and efficient programming language, Go language has also shown strong potential in mobile application development. This article will introduce in detail how to use Go language to develop mobile applications, and attach specific code examples to help readers get started quickly and start developing their own mobile applications. 1. Preparation Before starting, we need to prepare the development environment and tools. head

Exploring Go language front-end technology: a new vision for front-end development Exploring Go language front-end technology: a new vision for front-end development Mar 28, 2024 pm 01:06 PM

As a fast and efficient programming language, Go language is widely popular in the field of back-end development. However, few people associate Go language with front-end development. In fact, using Go language for front-end development can not only improve efficiency, but also bring new horizons to developers. This article will explore the possibility of using the Go language for front-end development and provide specific code examples to help readers better understand this area. In traditional front-end development, JavaScript, HTML, and CSS are often used to build user interfaces

Summary of the five most popular Go language libraries: essential tools for development Summary of the five most popular Go language libraries: essential tools for development Feb 22, 2024 pm 02:33 PM

Summary of the five most popular Go language libraries: essential tools for development, requiring specific code examples. Since its birth, the Go language has received widespread attention and application. As an emerging efficient and concise programming language, Go's rapid development is inseparable from the support of rich open source libraries. This article will introduce the five most popular Go language libraries. These libraries play a vital role in Go development and provide developers with powerful functions and a convenient development experience. At the same time, in order to better understand the uses and functions of these libraries, we will explain them with specific code examples.

Which Linux distribution is best for Android development? Which Linux distribution is best for Android development? Mar 14, 2024 pm 12:30 PM

Android development is a busy and exciting job, and choosing a suitable Linux distribution for development is particularly important. Among the many Linux distributions, which one is most suitable for Android development? This article will explore this issue from several aspects and give specific code examples. First, let’s take a look at several currently popular Linux distributions: Ubuntu, Fedora, Debian, CentOS, etc. They all have their own advantages and characteristics.

Which framework is best suited for VSCode development? Which framework is best suited for VSCode development? Mar 25, 2024 pm 02:03 PM

VSCode is a powerful, flexible, and easy-to-extend open source code editor that is widely favored by developers. It supports many programming languages ??and frameworks to meet different project needs. However, the advantages of VSCode may be different for different frameworks. This article will discuss the applicability of VSCode in the development of different frameworks and provide specific code examples. 1.ReactReact is a popular JavaScript library used for building user interfaces. When developing projects using React,

Comprehensive Guide: Detailed Java Virtual Machine Installation Process Comprehensive Guide: Detailed Java Virtual Machine Installation Process Jan 24, 2024 am 09:02 AM

Essentials for Java development: Detailed explanation of Java virtual machine installation steps, specific code examples required. With the development of computer science and technology, the Java language has become one of the most widely used programming languages. It has the advantages of cross-platform and object-oriented, and has gradually become the preferred language for developers. Before using Java for development, you first need to install the Java Virtual Machine (JavaVirtualMachine, JVM). This article will explain in detail the installation steps of the Java virtual machine and provide specific code examples.

See all articles