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.mzph.cn/news/252337.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

旋转三维平面与某一坐标平面平行

在上一篇文章&#xff08;https://blog.csdn.net/weixin_38636815/article/details/109495227&#xff09;中我写了如何使用ceres&#xff0c;根据一系列的点来拟合一个平面&#xff0c;很难保证ORB-SLAM输出的轨迹严格与某一个坐标平面平行&#xff0c;所以这篇文章我我将说一…

windows下配置opencv

我的windows下是使用的一个镜像安装的vs2015&#xff0c;然后在vs上编译工程需要使用opencv时&#xff0c;需要在工程中配置opencv 新建一个C工程&#xff0c;按照下面的步骤进行配置。 设置opencv的环境变量 “此电脑”右键点击“属性”-->选择“高级系统设置”-->选…

面试时,面试官到底在考察什么?

作者&#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;开源、高扩展、高可用。 基于分布式文件…

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 $ $< : …

跨域问题

一、为什么会有跨域问题&#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;一直没找到资…

基于django的视频点播网站开发-step11-后台用户管理功能...

用户管理功能&#xff0c;包含用户添加、列表展示、编辑、删除四大功能。下面我们一一揭晓。 用户添加 我们先实现用户添加功能&#xff0c;我们现在urls.py下添加相关的路由 path(user_add/, views.UserAddView.as_view(), nameuser_add), path(user_list/, views.UserListVie…

分布式之数据库和缓存双写一致性方案解析

先做一个说明&#xff0c;从理论上来说&#xff0c;给缓存设置过期时间&#xff0c;是保证最终一致性的解决方案。这种方案下&#xff0c;我们可以对存入缓存的数据设置过期时间&#xff0c;所有的写操作以数据库为准&#xff0c;对缓存操作只是尽最大努力即可。也就是说如果数…

‘(‘:illegal token on right side of ‘::‘

背景&#xff1a;想整理升级一下代码&#xff0c;添加了两个类&#xff0c;再一编译代码&#xff0c;出现了好多这样的错误提示“(:illegal token on right side of ::”&#xff0c;我很纳闷这是啥问题&#xff0c;我就使用“注释法”来定位出错的位置&#xff0c;我发现把所有…

虹软免费人脸识别SDK注册指南

2019独角兽企业重金招聘Python工程师标准>>> 成为开发者三步完成账号的基本注册与认证&#xff1a; STEP1:点击注册虹软AI开放平台右上角注册选项&#xff0c;完成注册流程。 STEP2:首次使用&#xff0c;登录后进入开发者中心&#xff0c;点击账号管理完成企业或者个…

C++中的类加多线程代码修炼

背景&#xff1a;现在在做一个目标跟踪的项目&#xff0c;需要实时的从工业相机中获取图像&#xff0c;然后再跟踪图像上的目标物&#xff0c;由于起初为了测试跟踪算法&#xff0c;就把“从相机获取图像”和“跟踪处理”都放在了主线程中&#xff0c;在实际测试时&#xff0c;…

vue的鼠标移入和移出

vue的鼠标移入和移出 需求&#xff08;鼠标到预约二维码显示&#xff0c;预约添加背景色&#xff09; 实现 <!--html部分--> <ul class"person_list"> //五个li标签皆是循环渲染出来的<li class"item" v-for"(n,index) in 5">…

聊聊flink的MemoryPool

为什么80%的码农都做不了架构师&#xff1f;>>> 序 本文主要研究一下flink的MemoryPool MemoryPool flink-runtime_2.11-1.7.2-sources.jar!/org/apache/flink/runtime/memory/MemoryManager.java abstract static class MemoryPool {abstract int getNumberOfAvai…

表达式求值

表达式求值问题 ①问题描述 表达式是数据运算的基本形式。人们的书写习惯是中缀式&#xff0c;如&#xff1a;1122*(7-4)/3。中缀式的计算按运算符的优先级及括号优先的原则&#xff0c;相同级别从左到右进行计算。表达式还有后缀式&#xff08;如&#xff1a;22 7 4 - * 3 / 1…