egg(110,111,112)--egg之微信支付

微信支付前的準備工作

準備工作

  1. 準備工作:個體工商戶、企業、政府及事業單位。

需要獲取內容

  1. appid:應用 APPID(必須配置,開戶郵件中可查看)
  2. MCHID:微信支付商戶號(必須配置,開戶郵件中可查看)
  3. KEY:API 密鑰,參考開戶郵件設置(必須配置,登錄商戶平臺自行設置)

express支付(測試)

向微信發送帶金額和標題參數的請求

//引入統一下單的api
var wechatPay = require('./module/wechatPay');var express = require('express');
var bodyParser = require('body-parser');
var xmlparser = require('express-xml-bodyparser');var app = new express();//xmlparser
app.use(xmlparser());app.use(express.static('./public'));
//使用中間件body-parser獲取post參數  
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());app.set('view engine', 'ejs');app.get('/order', function(req, res) {var openid = '';var config = {mch_id: '1502539541',wxappid: "wx7bf3787c783116e4",wxpaykey: 'zhongyuantengitying6666666666666'}var pay = new wechatPay(config);pay.createOrder({openid: openid,notify_url: 'http://118.123.14.36:8000/notifyUrl', //微信支付完成后的回調out_trade_no: new Date().getTime(), //訂單號attach: '名稱',body: '購買信息',total_fee: '1', // 此處的額度為分spbill_create_ip: req.connection.remoteAddress.replace(/::ffff:/, '')}, function(error, responseData) {console.log('11111111');console.log(responseData);if (error) {console.log(error);}res.json(responseData); /*簽名字段*/});
})app.listen(8000, function() {console.log('port 8000 is running!');
});

回調里有支付url

clipboard.png

把url轉成二維碼

clipboard.png

手機掃碼支付

支付頁面有金額和標題信息
clipboard.png

egg微信支付(真實)流程

  1. 調用統一下單接口生成預支付交易,獲取 code_url
  2. 用 code_url 生成二維碼
  3. 支付成功后監聽服務器的異步通知,然后處理訂單

掃碼支付前

微信支付js封裝包

applibwechatPay.js
/** @Descrition : wechat 微信支付功能*/var url = require('url');
var queryString = require('querystring');
var crypto = require('crypto');
var request = require('request');
var xml2jsparseString = require('xml2js').parseString;// wechat 支付類 (使用 es6 的語法)
class WechatPay {/*構造函數  */constructor(config) {this.config = config;}/*** 獲取微信統一下單參數*/getUnifiedorderXmlParams(obj) {var body = '<xml> ' +'<appid>' + this.config.wxappid + '</appid> ' +'<attach>' + obj.attach + '</attach> ' +'<body>' + obj.body + '</body> ' +'<mch_id>' + this.config.mch_id + '</mch_id> ' +'<nonce_str>' + obj.nonce_str + '</nonce_str> ' +'<notify_url>' + obj.notify_url + '</notify_url>' +'<openid>' + obj.openid + '</openid> ' +'<out_trade_no>' + obj.out_trade_no + '</out_trade_no>' +'<spbill_create_ip>' + obj.spbill_create_ip + '</spbill_create_ip> ' +'<total_fee>' + obj.total_fee + '</total_fee> ' +'<trade_type>' + obj.trade_type + '</trade_type> ' +'<sign>' + obj.sign + '</sign> ' +'</xml>';return body;}/*** 獲取微信統一下單的接口數據*/getPrepayId(obj) {var that = this;// 生成統一下單接口參數var UnifiedorderParams = {appid: this.config.wxappid,attach: obj.attach,body: obj.body,mch_id: this.config.mch_id,nonce_str: this.createNonceStr(),notify_url: obj.notify_url, // 微信付款后的回調地址openid: obj.openid, //改out_trade_no: obj.out_trade_no, //new Date().getTime(), //訂單號spbill_create_ip: obj.spbill_create_ip,total_fee: obj.total_fee,// trade_type : 'JSAPI',trade_type: 'NATIVE'// sign : getSign(),};// 返回 promise 對象return new Promise(function(resolve, reject) {// 獲取 sign 參數UnifiedorderParams.sign = that.getSign(UnifiedorderParams);var url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';request.post({ url: url, body: JSON.stringify(that.getUnifiedorderXmlParams(UnifiedorderParams)) }, function(error, response, body) {var prepay_id = '';if (!error && response.statusCode == 200) {// 微信返回的數據為 xml 格式, 需要裝換為 json 數據, 便于使用xml2jsparseString(body, { async: true }, function(error, result) {if (error) {console.log(error);reject(error);} else {// prepay_id = result.xml.prepay_id[0];   //小程序支付返回這個console.log(result);var code_url = result.xml.code_url[0];resolve(code_url);}});} else {console.log(body);reject(body);}});})}/*** 獲取微信支付的簽名* @param payParams*/getSign(signParams) {// 按 key 值的ascll 排序var keys = Object.keys(signParams);keys = keys.sort();var newArgs = {};keys.forEach(function(val, key) {if (signParams[val]) {newArgs[val] = signParams[val];}})var string = queryString.stringify(newArgs) + '&key=' + this.config.wxpaykey;// 生成簽名return crypto.createHash('md5').update(queryString.unescape(string), 'utf8').digest("hex").toUpperCase();}/*** 微信支付的所有參數* @param req 請求的資源, 獲取必要的數據* @returns {{appId: string, timeStamp: Number, nonceStr: *, package: string, signType: string, paySign: *}}*/getBrandWCPayParams(obj, callback) {var that = this;var prepay_id_promise = that.getPrepayId(obj);prepay_id_promise.then((prepay_id) => {var prepay_id = prepay_id;var wcPayParams = {"appId": this.config.wxappid, //公眾號名稱,由商戶傳入"timeStamp": parseInt(new Date().getTime() / 1000).toString(), //時間戳,自1970年以來的秒數"nonceStr": that.createNonceStr(), //隨機串                 // 通過統一下單接口獲取// "package" : "prepay_id="+prepay_id,   //小程序支付用這個"code_url": prepay_id,"signType": "MD5", //微信簽名方式:};wcPayParams.paySign = that.getSign(wcPayParams); //微信支付簽名callback(null, wcPayParams);}, function(error) {callback(error);});}/*** 獲取隨機的NonceStr*/createNonceStr() {return Math.random().toString(36).substr(2, 15);};//獲取微信的 AccessToken   openidgetAccessToken(code, cb) {var that = this;var getAccessTokenUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + this.config.wxappid + "&secret=" + this.config.wxappsecret + "&code=" + code + "&grant_type=authorization_code";request.post({ url: getAccessTokenUrl }, function(error, response, body) {if (!error && response.statusCode == 200) {if (40029 == body.errcode) {cb(error, body);} else {body = JSON.parse(body);cb(null, body);}} else {cb(error);}});}/*** 創建訂單*/createOrder(obj, cb) {this.getBrandWCPayParams(obj, function(error, responseData) {if (error) {cb(error);} else {cb(null, responseData);}});}
}module.exports = WechatPay;

config

configconfig.default.js
    // 微信支付的配置exports.weixinPayConfig = {mch_id: '1502539541',wxappid: "wx7bf3787c783116e4",wxpaykey: 'zhongyuantengitying6666666666666'}exports.weixinpayBasicParams = {//注意回調地址必須在  微信商戶平臺配置notify_url: "http://video.apiying.com/weixinpay/weixinpayNotify"}

router

 router.get('/weixinpay/pay', initMiddleware, controller.default.weixinpay.pay);

controller

appcontrollerdefaultweixinpay.js
'use strict';const Controller = require('egg').Controller;class WeixinpayController extends Controller {async pay() {var d = new Date();const data = {title: '辣條111',out_trade_no: d.getTime().toString(),price: '0.1'}var code_url = await this.service.weixinpay.doPay(data);//調用方法生成二維碼var qrImage = await this.service.weixinpay.qrImage(code_url);this.ctx.type = 'image/png';this.ctx.body = qrImage;}
}module.exports = WeixinpayController;

service

appserviceweixinpay.js
'use strict';var wechatPay = require('../lib/wechatPay.js');
const qr = require('qr-image');
const Service = require('egg').Service;class WeixinpayService extends Service {async doPay(orderData) {return new Promise((resove) => {var pay = new wechatPay(this.config.weixinPayConfig);var notify_url = this.config.weixinpayBasicParams.notify_url;var out_trade_no = orderData.out_trade_no;var title = orderData.title;var price = orderData.price * 100;var ip = this.ctx.request.ip.replace(/::ffff:/, '');pay.createOrder({openid: '',notify_url: notify_url, //微信支付完成后的回調out_trade_no: out_trade_no, //訂單號attach: title,body: title,total_fee: price.toString(), // 此處的額度為分spbill_create_ip: ip}, function(error, responseData) {console.log(responseData);if (error) {console.log(error);}resove(responseData.code_url)});})}async qrImage(url) {var qrimg = qr.image(url, { type: 'png' });return qrimg;}
}module.exports = WeixinpayService;

view

appviewdefaultconfirm.html
                <div class="payment-box "><div class="payment-body"><ul class="clearfix payment-list J_paymentList J_linksign-customize"><li id="weixinPay"><img src="//c1.mifile.cn/f/i/16/pay/weixinpay0701.png" alt="微信支付" style="margin-left: 0;"></li><li class="J_bank" id="alipay"><a target="_blank" href="/alipay/pay?id=<%=orderResult._id%>"> <img src="//s01.mifile.cn/i/banklogo/payOnline_zfb.png?ver2015" alt="支付寶" style="margin-left: 0;"></a></li></ul></div></div>
    <div class="modal fade" id="weixinPayModel" tabindex="-1" role="dialog"><div class="modal-dialog" role="document"><div class="modal-content"><div class="modal-header"><button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button><h4 class="modal-title" id="myModalLabel">微信支付</h4></div><div class="modal-body"><img class="lcode" src="/weixinpay/pay?id=1242141244" /><img class="rphone" src="/public/default/image/phone.png" /></div></div></div></div>
            $("#weixinPay").click(function() {$('#weixinPayModel').modal('show');})

效果

把訂單信息通過微信支付js,轉成url,再把url轉成二維碼
clipboard.png

clipboard.png

clipboard.png

掃碼支付后

router

    //異步通知   注意關閉csrf驗證router.post('/weixinpay/weixinpayNotify', initMiddleware, xmlparseMiddleware, controller.default.weixinpay.weixinpayNotify);

config

configconfig.default.js

csrf

config.security = {csrf: {// 判斷是否需要 ignore 的方法,請求上下文 context 作為第一個參數ignore: ctx => {if (ctx.request.url == '/admin/goods/goodsUploadImage' || ctx.request.url == '/admin/goods/goodsUploadPhoto' || ctx.request.url == '/pass/doLogin' || ctx.request.url == '/user/addAddress' || ctx.request.url == '/user/editAddress' || ctx.request.url == '/admin/goods/goodsUploadPhoto' || ctx.request.url == '/weixinpay/weixinpayNotify') {return true;}return false;}}}

controller

appcontrollerdefaultweixinpay.js
    //異步通知async weixinpayNotify(){let that = this;     let data = '';               this.ctx.req.on('data',function(chunk){data += chunk;});this.ctx.req.on('end',function(){xml2js(data,{explicitArray:false}, function (err, json) {console.log(json);//這里的json便是xml轉為json的內容var mySign=that.service.weixinpay.weixinpayNotify(json.xml);console.log(mySign);console.log('-------------');console.log(json.xml.sign);});});}

service

appserviceweixinpay.js
    weixinpayNotify(params) {var pay = new wechatPay(this.config.weixinPayConfig);var notifyObj = params;var signObj = {};for (var attr in notifyObj) {if (attr != 'sign') {signObj[attr] = notifyObj[attr]}}var sign = pay.getSign(signObj);return sign;}

回調信息

clipboard.png

支付后跳轉

微信支付后,支付寶支付后

微信支付后不會自動跳轉

clipboard.png

流程

5秒鐘判斷一次狀態
clipboard.png

修改支付狀態和訂單狀態為1(成功)
clipboard.png

支付狀態和訂單狀態為1(成功),則跳轉到訂單頁面
clipboard.png

router

 //檢測訂單是否支付router.get('/buy/getOrderPayStatus', initMiddleware, userauthMiddleware, controller.default.buy.getOrderPayStatus);router.get(' /user/order', initMiddleware, userauthMiddleware, controller.default.user.order);

controller

appcontrollerdefaultbuy.js
    async getOrderPayStatus() {/*1、獲取訂單號2、查詢當前訂單的支付狀態3、如果支付 返回成功   如果沒有支付返回失敗信息*/var id = this.ctx.request.query.id;if (id) {try {var orderReuslt = await this.ctx.model.Order.find({ "_id": id });if (orderReuslt && orderReuslt[0].pay_status == 1 && orderReuslt[0].order_status == 1) {this.ctx.body = {success: true,message: '已支付'}} else {this.ctx.body = {success: false,message: '未支付'}}} catch (error) {this.ctx.body = {success: false,message: '未支付'}}} else {this.ctx.body = {success: false,message: '未支付'}}}

view

appviewdefaultconfirm.html
            setInterval(function() {$.get('/buy/getOrderPayStatus?id=<%=id%>', function(response) {console.log(response);if (response.success) {location.href = '/user/order'}})}, 5000);

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/252337.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/252337.shtml
英文地址,請注明出處:http://en.pswp.cn/news/252337.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

解決圖片跨域問題

var imgs new Image(); imgs.crossOrigin "Anonymous"; //注意存放順序 imgs.src "http://192.168.0.107/ZHCX/CGZSIMG/1.jpg"; imgs.onload function () { var canvas document.createElement(canvas); canvas.width imgs.width; canvas.height i…

旋轉三維平面與某一坐標平面平行

在上一篇文章&#xff08;https://blog.csdn.net/weixin_38636815/article/details/109495227&#xff09;中我寫了如何使用ceres&#xff0c;根據一系列的點來擬合一個平面&#xff0c;很難保證ORB-SLAM輸出的軌跡嚴格與某一個坐標平面平行&#xff0c;所以這篇文章我我將說一…

elasticsearch的插件安裝

目前使用的是2.4.5版本的es 安裝的時候注意以下幾點 : 1.如果想所有的ip都能訪問es,需要修改config下的elasticsearch.yml.修改如下 network.host0.0.0.02.安裝查詢插件 : 進入es的安裝目錄,執行以下命令 ./bin/plugin install mobz/elasticsearch-head3.安裝刪除插件 目前不支…

let const緩存for循環的中間變量

es5中使用在for-in for循環中注冊異步事件&#xff0c;異步事件中的i總是最后一個值。使用es6的let const可以解決 let obj {a: 1,b: 1,c: 1 }// es5 for循環中 var聲明 i let funcs [] for (var key in obj) {funcs.push(() > {console.log(key)}) } funcs.forEach(func …

BZOJ1439 : YY的問題

考慮容斥&#xff0c;枚舉哪些不存在的邊選中了&#xff0c;剩下的不管&#xff0c;則可以用組合數計算方案數。 時間復雜度$O(m2^mnm)$。 #include<cstdio> const int N550,B10000,MAXL350; int n,m,S,i,j,e[N][2],g[N],f[N]; inline int max(int a,int b){return a>…

windows下配置opencv

我的windows下是使用的一個鏡像安裝的vs2015&#xff0c;然后在vs上編譯工程需要使用opencv時&#xff0c;需要在工程中配置opencv 新建一個C工程&#xff0c;按照下面的步驟進行配置。 設置opencv的環境變量 “此電腦”右鍵點擊“屬性”-->選擇“高級系統設置”-->選…

關于spring MVC中加載多個validator的方法。

首先講下什么叫做validator&#xff1a; validator是驗證器&#xff0c;可以驗證后臺接受的數據&#xff0c;對數據做校驗。 SpringMVC服務器驗證有兩種方式,一種是基于Validator接口,一種是使用Annotaion JSR-303標準的驗證。 1.使用Annotaion JSR-303標準的驗證 使用這個需要…

面試時,面試官到底在考察什么?

作者&#xff1a;白海飛出處&#xff1a;極客時間《面試現場》專欄 先看一段面試對話&#xff0c;“大面”是一位久經沙場的面試官&#xff0c;小明就是今天的應聘者。一通面試下來&#xff0c;前面的技術問題小明都對答如流&#xff0c;雙方相談甚歡&#xff0c;接下來面試官“…

NoSQL-MongoDB with python

前言&#xff1a; MongoDB&#xff0c;文檔存儲型數據庫&#xff08;document store&#xff09;。NoSQL數據庫中&#xff0c;它獨占鰲頭&#xff0c;碾壓其他的NoSQL數據庫。 使用C開發的&#xff0c;性能僅次C。與redis一樣&#xff0c;開源、高擴展、高可用。 基于分布式文件…

RHCS

云計算與大數據 黑洞 RHCS(概念篇) 一、 什么是RHCS RHCS是Red Hat Cluster Suite的縮寫&#xff0c;也就是紅帽子集群套件&#xff0c;RHCS是一個能夠提供高可用性、高可靠性、負載均衡、存儲共享且經濟廉價的集群工具集合&#xff0c;它將集群系統中三大集群架構融合一體&…

深度圖壓縮之-高低8位拆分保存

使用kinect相機保存數據&#xff0c;為了減少保存的數據集量&#xff0c;對圖像進行壓縮。將彩色圖像直接壓縮成.mp4格式&#xff0c;此時圖像上的一些高頻信息會被損失掉。 為了能夠讓深度圖有比較高的保真度&#xff0c;減少深度圖上高頻信息的損失&#xff0c;我們將16位的…

linux 一個超簡單的makefile

2019獨角獸企業重金招聘Python工程師標準>>> makefile 自動化變量&#xff1a; $ : 規則的目標文件名 例如&#xff1a;main:main.o test.o g -Wall -g main.o test.o -o main 可以寫成&#xff1a; main:main.o test.o g -Wall -g main.o test.o -o $ $< : …

poj2480(利用歐拉函數的積性求解)

題目鏈接: http://poj.org/problem?id2480 題意&#xff1a;∑gcd(i, N) 1<i <N&#xff0c;就這個公式&#xff0c;給你一個n&#xff0c;讓你求sumgcd(1,n)gcd(2,n)gcd(3,n)…………gcd(n-1,n)gcd(n,n),&#xff08;1<n<2^31&#xff09;是多少&#xff1f; 放…

跨域問題

一、為什么會有跨域問題&#xff1f; 是因為瀏覽器的同源策略是對ajax請求進行阻攔了&#xff0c;但是不是所有的請求都給做跨域&#xff0c;像是一般的href屬性&#xff0c;a標簽什么的都不攔截。 二、解決跨域問題的兩種方式 JSONPCORS 三、JSONP 先簡單來說一下JSONP&#x…

PAT A1052

這個需要注意的是相關的string轉整數或者double的函數&#xff1b;詳見這個鏈接blog #include <iostream> #include <string> using namespace std; bool isPrime(int n) {if (n 0 || n 1) return false;for (int i 2; i * i < n; i)if (n % i 0) return fa…

php審計學習:xdcms2.0.8注入

注入點Fields: 注冊頁面會引用如下方法: $fields 變量是從 $fields$_POST[fields]; 這里獲取&#xff0c; 在代碼里沒有過濾。 打印 fields 數據查看: 從代碼上看 $field_sql.",{$k}{$f_value}"; 最終會變成: ,truename111111,email12345 因為 $field_sql 最終會引入…

windows下安裝python和Python-opencv

背景&#xff1a;目前基于python的圖像處理和機器視覺的研究還挺多&#xff0c;最近不是在研究目標檢測和目標跟蹤的算法&#xff0c;由于檢測和跟蹤的環境比較簡單所以從不帶學習的跟蹤方法&#xff0c;在搜索資料時搜到這個網站&#xff0c;是對opencv中的目標跟蹤算法的一個…

捋一捋js面向對象的繼承問題

說到面向對象這個破玩意&#xff0c;曾經一度我都處于很懵逼的狀態&#xff0c;那么面向對象究竟是什么呢&#xff1f;其實說白了&#xff0c;所謂面向對象&#xff0c;就是基于類這個概念&#xff0c;來實現封裝、繼承和多態的一種編程思想罷了。今天我們就來說一下這其中繼承…

java8簡單入門

1、介紹 本片文章會從一下幾個知識點進行介紹&#xff1a; 函數式接口 FunctionalInterfaceLambda 表達式函數引用 Function ReferenceStream看了幾篇關于 java8 入門的例子&#xff0c;其中引入了許多令人期待已久的特性&#xff08;雖然我沒有過這樣的體會&#xff09;&#…

玩轉帶外觸發的單目相機之一

背景&#xff1a;去年開始研究vins,但是只是用了普通的相機&#xff0c;然后將IMU和相機粘在一起&#xff0c;然后就是聯合標定相機和IMU。VINS使用的相機是帶有外觸發的&#xff0c;還進行了相機和IMU的硬件時間同步。當時我特別想買個帶外觸發的相機&#xff0c;一直沒找到資…