${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> 串有問題,可以提前在微信提供的簽名校驗工具里先校驗一遍,看看是否能通過。<\/p>\n

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

    因為需要跟微信服務端發(fā)請求,所以我選擇了 axios<\/code> 這個在瀏覽器端和node端都能發(fā)起ajax請求的庫。<\/p>\n

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

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

    微信會給我們返回一個諸如下面格式的 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

    我們的目標是轉(zhuǎn)為如下的js對象,好讓我們用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

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

    \/\/?將XML轉(zhuǎn)為JS對象\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

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

    const?axios?=?require('axios')\r\nconst?url?=?'https:\/\/api.mch.weixin.qq.com\/pay\/unifiedorder'?\/\/?微信服務端地址\r\nconst?pay?=?async?(ctx)?=>?{\r\n?const?form?=?ctx.request.body?\/\/?通過前端傳來的數(shù)據(jù)\r\n?const?orderNo?=?'XXXXXXXXXXXXXXXX'?\/\/?不重復的訂單號\r\n?const?fee?=?form.fee?\/\/?通過前端傳來的費用值\r\n?const?data?=?xmlBody(fee,?orderNo)?\/\/?fee是費用,orderNo是訂單號(唯一)\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:?'請求成功',\r\n?code_url:?res.code_url,?\/\/?code_url就是用于生成支付二維碼的鏈接\r\n?order_no:?orderNo?\/\/?訂單號\r\n?}\r\n?}\r\n?ctx.body?=?{\r\n?success:?false,\r\n?message:?'請求失敗'\r\n?}\r\n}\r\nrouter.post('\/api\/pay',?pay)\r\nmodule.exports?=?router<\/pre>\n

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

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

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

    然后到頁面底下掛載這個路由:<\/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> 來請求二維碼數(shù)據(jù)啦。(如果有跨域需要自己考慮解決跨域方案,可以跟Koa放在同域里,也可以開一層proxy來轉(zhuǎn)發(fā),也可以開CORS頭等等)<\/p>\n

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

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

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

    在前端,我使用的是 @xkeshi\/vue-qrcode 這個庫來生成二維碼。它調(diào)用特別簡單:<\/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

    付款成功自動刷新頁面<\/strong><\/span><\/p>\n

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

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

    一種是后端一直開著接口,等微信主動給后端的 notify_url<\/code> 發(fā)起post請求,告訴后端支付結(jié)果,讓后端寫入數(shù)據(jù)庫。然后此時前端向后端輪詢的時候應該是去數(shù)據(jù)庫取輪詢該訂單的支付結(jié)果,如果支付成功就關(guān)閉Dialog。<\/p>\n

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

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

    所以 付款成功自動刷新頁面<\/code> 這個部分我們分為兩個部分來說:<\/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里寫一個查詢訂單信息的方法:<\/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', { \/\/ 向后端請求訂單支付信息\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的時候,這個方法就啟用了。然后就開始輪詢。我訂了一個時間,200s后如果還是沒有付款信息也自動刷新頁面。實際上你可以自己根據(jù)項目的需要來定義這個時間。<\/p>\n

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

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

    先來寫最關(guān)鍵的微信的推送請求處理。由于我們接收微信的請求是在Koa的路由里,并且是以流的形式傳輸?shù)?。需要讓Koa支持解析xml格式的body,所以需要安裝一個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ā)送的請求類型是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> 的形式回傳的,會調(diào)試半天。。<\/p>\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)掌握了方法,更多精彩請關(guān)注php中文網(wǎng)其它相關(guān)文章!<\/p>\n

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

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

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

    亚洲国产日韩欧美一区二区三区,精品亚洲国产成人av在线,国产99视频精品免视看7,99国产精品久久久久久久成人热,欧美日韩亚洲国产综合乱

    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'?//?服務端可訪問的域名和接口
    const?server_ip?=?'xx.xx.xx.xx'?//?服務端的ip地址
    const?trade_type?=?'NATIVE'?//?NATIVE對應的是二維碼掃碼支付
    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 是要充值的費用,以分為單位。比如要充值1塊錢, fee 就是100。ip是個比較隨意的選項,只要符合規(guī)則的ip經(jīng)過測試都是可以的,下文里我用的是 server_ip 。 nonce 就是微信要求的不重復的32位以內(nèi)的字符串,通??梢允褂糜唵翁柕任ㄒ粯俗R的字符串。

    由于跟微信的服務器交流都是用xml來交流,所以現(xiàn)在我們要手動組裝一下post請求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 串有問題,可以提前在微信提供的簽名校驗工具里先校驗一遍,看看是否能通過。

    發(fā)送請求

    因為需要跟微信服務端發(fā)請求,所以我選擇了 axios 這個在瀏覽器端和node端都能發(fā)起ajax請求的庫。

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

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

    微信會給我們返回一個諸如下面格式的 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>

    我們的目標是轉(zhuǎn)為如下的js對象,好讓我們用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'?//?用于生成支付二維碼的鏈接
    }

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

    //?將XML轉(zhuǎn)為JS對象
    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)
    ?}
    ?})
    ?})
    }

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

    const?axios?=?require('axios')
    const?url?=?'https://api.mch.weixin.qq.com/pay/unifiedorder'?//?微信服務端地址
    const?pay?=?async?(ctx)?=>?{
    ?const?form?=?ctx.request.body?//?通過前端傳來的數(shù)據(jù)
    ?const?orderNo?=?'XXXXXXXXXXXXXXXX'?//?不重復的訂單號
    ?const?fee?=?form.fee?//?通過前端傳來的費用值
    ?const?data?=?xmlBody(fee,?orderNo)?//?fee是費用,orderNo是訂單號(唯一)
    ?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:?'請求成功',
    ?code_url:?res.code_url,?//?code_url就是用于生成支付二維碼的鏈接
    ?order_no:?orderNo?//?訂單號
    ?}
    ?}
    ?ctx.body?=?{
    ?success:?false,
    ?message:?'請求失敗'
    ?}
    }
    router.post('/api/pay',?pay)
    module.exports?=?router

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

    找到之前默認的兩個路由,一個 index ,一個 user

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

    然后到頁面底下掛載這個路由:

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

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

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

    展示支付二維碼

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

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

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

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

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

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

    文本是我自己添加的

    ?

    付款成功自動刷新頁面

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

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

    一種是后端一直開著接口,等微信主動給后端的 notify_url 發(fā)起post請求,告訴后端支付結(jié)果,讓后端寫入數(shù)據(jù)庫。然后此時前端向后端輪詢的時候應該是去數(shù)據(jù)庫取輪詢該訂單的支付結(jié)果,如果支付成功就關(guān)閉Dialog。

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

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

    所以 付款成功自動刷新頁面 這個部分我們分為兩個部分來說:

    前端部分

    Vue的data部分

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

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

    //?...
    handleCheckBill?()?{
    ?return?setTimeout(()?=>?{
    ?if?(!this.payStatus?&&?this.retryCount?< 120) {
     this.retryCount += 1
     axios.post(&#39;/api/check-bill&#39;, { // 向后端請求訂單支付信息
     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的時候,這個方法就啟用了。然后就開始輪詢。我訂了一個時間,200s后如果還是沒有付款信息也自動刷新頁面。實際上你可以自己根據(jù)項目的需要來定義這個時間。

    后端部分

    前端到后端只有一個接口,但是后端有兩個接口。一個是用來接收微信的推送,一個是用來接收前端的查詢請求。

    先來寫最關(guān)鍵的微信的推送請求處理。由于我們接收微信的請求是在Koa的路由里,并且是以流的形式傳輸?shù)摹P枰孠oa支持解析xml格式的body,所以需要安裝一個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ā)送的請求類型是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 的形式回傳的,會調(diào)試半天。。

    接下來這個就是比較簡單的給前端回傳的了。

    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)掌握了方法,更多精彩請關(guān)注php中文網(wǎng)其它相關(guān)文章!

    推薦閱讀:

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

    如何操作Koa2微信公眾號實現(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)

    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