Win10环境前后端分离项目基于Vue.js+Django+Python3实现微信(wechat)扫码支付流程(2021年最新攻略)
原文转载自「刘悦的技术博客」https://v3u.cn/a_id_182
之前的一篇文章:mpvue1.0+python3.7+Django2.0.4实现微信小程序的支付功能,主要介绍了微信小程序内部支付的流程,然而实际上微信小程序有一定的局限性,也就是用户范围仅限于小程序内部生态圈,在生活中真正具有广泛性、高效性、使用方便性的支付方式还得是扫码支付,扫码的优点在于推广成本低,上至钓鱼台国宾馆,下至发廊地摊都能用,打印出来就完事了,而相比其他支付方式,现金的找零及假钞问题,信用卡的办理门槛、pos机的沉没成本,就算微信可集成的h5支付和小程序支付,奈何很多老年人根本不会用小程序和手机浏览器,更别说再进行支付操作了,所以基于二维码的扫码支付的确是非常符合国情的。
本次我们使用前后端分离项目Vue.js+Django来集成微信的扫码支付功能,体验一下21世纪泛用性最高的支付方式,首先注册微信公众平台:https://mp.weixin.qq.com
获得开发者id和秘钥(appid & appsecret)
同时确保获取微信支付接口的权限:
随后注册微信支付商户平台:https://pay.weixin.qq.com/
获取微信支付的商户号(在账户信息页面):
获取微信支付接口的秘钥(账户中心->api安全):
同时在产品中心->开发配置页面,将支付域名配置好:
这里不像微信小程序,小程序只能允许https协议接口,而扫码支付域名既支持https也支持http,非常方便,同时注意域名必须是一个备案域名。
至此,微信支付的前置操作就搞定了,下面我们来编写后台接口wx_pay.py,首先导入依赖的库和一些工具方法:
import requests
from django.http import HttpResponse, HttpResponseRedirect import random
import time
import hashlib import qrcode
from bs4 import BeautifulSoup def trans_xml_to_dict(data_xml): soup = BeautifulSoup(data_xml, features='xml') xml = soup.find('xml') # 解析XML if not xml: return {} data_dict = dict([(item.name, item.text) for item in xml.find_all()]) return data_dict def trans_dict_to_xml(data_dict): # 定义字典转XML的函数 data_xml = [] for k in sorted(data_dict.keys()): # 遍历字典排序后的key v = data_dict.get(k) # 取出字典中key对应的value if k == 'detail' and not v.startswith('<![CDATA['): # 添加XML标记 v = '<![CDATA[{}]]>'.format(v) data_xml.append('<{key}>{value}</{key}>'.format(key=k, value=v)) return '<xml>{}</xml>'.format(''.join(data_xml)) # 返回XML def get_sign(data_dict, key): # 签名函数,参数为签名的数据和密钥 params_list = sorted(data_dict.items(), key=lambda e: e[0], reverse=False) # 参数字典倒排序为列表 params_str = "&".join(u"{}={}".format(k, v) for k, v in params_list) + '&key=' + key # 组织参数字符串并在末尾添加商户交易密钥 md5 = hashlib.md5() # 使用MD5加密模式 md5.update(params_str.encode()) # 将参数字符串传入 sign = md5.hexdigest().upper() # 完成加密并转为大写 return sign
qrcode模块用来生成二维码,bs4模块用来将微信接口返回的xml解析成json,在21世纪的第二十个年头,微信接口居然还在使用原始的xml,这种反人类行为实在不能理解。
接下来我们来编写支付逻辑,参考微信官方文档:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_5&index=3
业务流程说明:
(1)商户后台系统根据用户选购的商品生成订单。
(2)用户确认支付后调用微信支付【统一下单API】生成预支付交易;
(3)微信支付系统收到请求后生成预支付交易单,并返回交易会话的二维码链接code_url。
(4)商户后台系统根据返回的code_url生成二维码。
(5)用户打开微信“扫一扫”扫描二维码,微信客户端将扫码内容发送到微信支付系统。
(6)微信支付系统收到客户端请求,验证链接有效性后发起用户支付,要求用户授权。
(7)用户在微信客户端输入密码,确认支付后,微信客户端提交授权。
(8)微信支付系统根据用户授权完成支付交易。
(9)微信支付系统完成支付交易后给微信客户端返回交易结果,并将交易结果通过短信、微信消息提示用户。微信客户端展示支付交易结果页面。
(10)微信支付系统通过发送异步消息通知商户后台系统支付结果。商户后台系统需回复接收情况,通知微信后台系统不再发送该单的支付通知。
(11)未收到支付通知的情况,商户后台系统调用【查询订单API】。
(12)商户确认订单已支付后给用户发货。
一望而知,我们需要调用微信的统一下单接口,文档:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=9_1
编写逻辑:
def wx_pay(request): url = 'https://api.mch.weixin.qq.com/pay/unifiedorder' # 微信扫码支付接口 key = '945bec********a8fbf7d7' #商户api秘钥 total_fee = 1 #支付金额,单位分 body = '123123' # 商品描述 out_trade_no = 'order_%s' % random.randrange(100000, 999999) # 订单编号 params = { 'appid': 'wx09*****f', # APPID 'mch_id': '16****08', # 商户号 'notify_url': 'http://wxpay.v3u.cn/wx_back/', # 支付域名回调地址 'product_id': 'goods_%s' % random.randrange(100000, 999999), # 商品编号 'trade_type': 'NATIVE', # 支付类型(扫码支付) 'spbill_create_ip': '114.254.176.137', # 发送请求服务器的IP地址 'total_fee': total_fee, # 订单总金额 'out_trade_no': out_trade_no, # 订单编号 'body': body, # 商品描述 'nonce_str': 'ibuaiVcKdpRxkhJA' # 字符串 } sign = get_sign(params, key) # 获取签名 params.setdefault('sign', sign) # 添加签名到参数字典 xml = trans_dict_to_xml(params) # 转换字典为XML response = requests.request('post', url, data=xml) # 以POST方式向微信公众平台服务器发起请求 data_dict = trans_xml_to_dict(response.content) # 将请求返回的数据转为字典 print(data_dict) qrcode_name = out_trade_no + '.png' # 支付二维码图片保存路径 if data_dict.get('return_code') == 'SUCCESS': # 如果请求成功 img = qrcode.make(data_dict.get('code_url')) # 创建支付二维码片 img.save('./' + qrcode_name) # 保存支付二维码 return HttpResponse(qrcode_name)
随后配置路由:
from myapp.wx_pay import wx_pay
from django.contrib.staticfiles.urls import staticfiles_urlpatterns # ... the rest of your URLconf goes here ...
urlpatterns = [ #定义超链接路由 re_path('^static/upload/(?P<path>.*)$',serve,{'document_root':'/static/upload/'}), path('wx_pay/', wx_pay),
]
启动django服务:
python manage.py runserver
访问http://localhost:8000/wx_pay/
没有问题,查看后台日志:
{'return_code': 'SUCCESS', 'return_msg': 'OK', 'appid': 'wx092344a76b9979ff', 'mch_id': '1602932608', 'nonce_str': 'bnJwGlXZ3eDSNgjs', 'sign': '2D81402DABEDF75E9A58F200FE7B6775', 'result_code': 'SUCCESS', 'prepay_id': 'wx1816114416896958d6f84177bd71da0000', 'trade_type': 'NATIVE', 'code_url': 'weixin://wxpay/bizpayurl?pr=JgBYgTS00'}
可以看到已经下单成功,不过订单状态处于预支付状态,同时检查二维码图片是否生成:
至此,后台逻辑基本搞定,下面就是如何在前端进行调用,同时让用户进行扫描操作,编写wx_pay.vue组件:
<template> <div> <center><h1>扫码支付</h1></center> <a-form-item v-bind="formItemLayout" label="金额"> <a-input v-model="money"/> </a-form-item> <a-form-item v-bind="tailFormItemLayout"> <a-button type="primary" html-type="submit" @click="submit"> 生成二维码 </a-button> </a-form-item> <a-form-item v-bind="formItemLayout" label="二维码"> <img :src="src" /> </a-form-item> </div> </template> <script> export default { data() { return { money:"1", src:"", formItemLayout: { labelCol: { xs: { span: 24 }, sm: { span: 8 }, }, wrapperCol: { xs: { span: 24 }, sm: { span: 16 }, }, }, tailFormItemLayout: { wrapperCol: { xs: { span: 24, offset: 0, }, sm: { span: 16, offset: 8, }, }, }, dataSource: [ { key: '0', name: 'Edward King 0', age: '32', address: 'London, Park Lane no. 0', }, { key: '1', name: 'Edward King 1', age: '32', address: 'London, Park Lane no. 1', }, ], columns: [ { title: 'name', dataIndex: 'name', }, { title: 'age', dataIndex: 'age', }, { title: 'address', dataIndex: 'address', }, { title: 'operation', dataIndex: 'operation', scopedSlots: { customRender: 'operation' }, }, ], }; }, methods: { submit:function(){ this.axios.get('http://localhost:8000/wx_pay/').then((result) =>{ console.log(result.data.img); this.src = "http://localhost:8000/static/upload/"+result.data.img }); }, onDelete(key) { console.log(this.dataSource[key]); } },
};
</script>
当用户点击按钮之后,旋即请求后端支付接口,将接口生成的二维码返回给前端,效果是这样的:
随后使用微信扫一扫功能进行扫码支付,需要注意的是,该二维码有效期只有五分钟,所以最好加上刷新功能。
支付成功之后,我们还需要对交易进行确认,所以根据微信官方文档,调用统一查询接口:
https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=9_2,根据接口文档编写逻辑:
def wx_check(request): #统一订单查询接口 url = "https://api.mch.weixin.qq.com/pay/orderquery" out_trade_no = "order_537236" #支付后的商户订单号 key = '945b******d7' # 商户api密钥 params = { 'appid': 'wx0*****ff', # APPID 'mch_id': '16*****08', # 商户号 'out_trade_no': out_trade_no, # 订单编号 'nonce_str': 'ibuaiVcKdpRxkhJA' # 随机字符串 } sign = get_sign(params, key) # 获取签名 params.setdefault('sign', sign) # 添加签名到参数字典 xml = trans_dict_to_xml(params) # 转换字典为XML response = requests.request('post', url, data=xml) # 以POST方式向微信公众平台服务器发起请求 data_dict = trans_xml_to_dict(response.content) # 将请求返回的数据转为字典 print(data_dict) return HttpResponse('ok')
这里需要注意的是,查询的订单编号可以使商户自己的订单编号,也可以是微信订单号,二者必取其一:
访问接口 http://localhost:8000/wx_check/
返回结果:
{'return_code': 'SUCCESS', 'return_msg': 'OK', 'appid': 'wx092344a76b9979ff', 'mch_id': '1602932608', 'nonce_str': 'BVoaDmxxADkpSFEl', 'sign': '23A86EB406B743E0C2C61C7E78DC9373', 'result_code': 'SUCCESS', 'openid': 'oy9q36f9Dpeokj9FWyN3j0znpIqE', 'is_subscribe': 'N', 'trade_type': 'NATIVE', 'bank_type': 'OTHERS', 'total_fee': '1', 'fee_type': 'CNY', 'transaction_id': '4200000806202012174121934231', 'out_trade_no': 'order_537236', 'attach': ' ', 'time_end': '20201217231553', 'trade_state': 'SUCCESS', 'cash_fee': '1', 'trade_state_desc': '支付成功', 'cash_fee_type': 'CNY'}
可以看到没有问题,但是由于涉及金钱业务,为了养成良好的测试习惯,最好登录商户后台再次确认:
结语:至此,整个微信扫码支付流程全部跑通,流程上比微信小程序支付逻辑要简单一些,同时由于不需要在线用户的openid,所以像微信小程序获取不到openid这样的大坑并不存在,后续会分享一些关于微信扫码订单退款的逻辑,搞笑的是,统一下单和查询接口没有并发限制,而申请退款居然有qps上的限制,所以退款流程应该会需要消息队列的介入。
原文转载自「刘悦的技术博客」 https://v3u.cn/a_id_182
Win10环境前后端分离项目基于Vue.js+Django+Python3实现微信(wechat)扫码支付流程(2021年最新攻略)相关推荐
- Win10环境前后端分离项目基于Vue.js+Tornado+Python3实现微信(wechat)扫码支付流程
在生活具有广泛性.高效性.使用方便性的支付方式是扫码支付,扫码的优点在于推广成本低,上至钓鱼台国宾馆,下至发廊地摊都能用,打印出来就完事了,而相比其他支付方式,现金的找零及假钞问题,信用卡的办理门槛. ...
- 基于web的前后端分离nodejs和vue.js医院分诊系统
(1)系统设置模块:包括权限管理和用户信息管理.此模块主要功能包括:添加.修改.删除和查看用户信息,给用户分配权限进行角色管理. (2)用户管理:用户进行登录和注册,进行挂号 (3)患者管理模块:此模 ...
- 前后端分离,基于vue+elementUI的动态菜单
制作动态菜单的思路: 就是当前用户登陆后,保存用户的信息,通过用户的id,去查找该用户对象的菜单.后台获取的菜单数据,最终传给前台形式就是父菜单里包含了所有的子菜单:并在前台登录成功后,把菜单数据取出 ...
- 前后端分离项目,vue+uni-app+php+mysql外卖点餐小程序系统 开题报告
毕业论文 基于Vue.js外卖点餐小程序系统 开题报告 学 院: 专 业: 年 级: 学生姓名: 指导教师: 黄菊华 XXXX大学本科生毕业论文(设计)开题报告书 姓 名 ...
- 前后端分离项目,vue+uni-app+php+mysql在线教育视频点播小程序系统 开题报告
毕业论文 基于Vue.js视频点播小程序系统 开题报告 学 院: 专 业: 年 级: 学生姓名: 指导教师: 黄菊华 XXXX大学本科生毕业论文(设计)开题报告书 姓 名 ...
- 前后端分离项目,vue+uni-app+php+mysql外卖点餐系统设计与实现(H5移动项目)
功能介绍 [后台管理员功能] 会员列表:查看所有注册会员信息,支持删除 录入资讯:录入资讯标题.内容等信息 管理资讯:查看已录入资讯列表,支持删除和修改 广告设置:上传图片和设置小程序首页轮播图广告地 ...
- 前后端分离项目,vue+uni-app+php+mysql教室预约系统(H5移动项目) 开题报告
毕业论文 基于Vue.js的教室预约系统(H5) 开题报告 学 院: 专 业: 年 级: 学生姓名: 指导教师: 黄菊华 XXXX大学本科生毕业论文(设计)开题报告书 姓 ...
- 前后端分离项目,vue+uni-app+php+mysql教室预约小程序系统 开题报告
毕业论文 基于Vue.js的教室预约小程序系统 开题报告 学 院: 专 业: 年 级: 学生姓名: 指导教师: 黄菊华 XXXX大学本科生毕业论文(设计)开题报告书 姓 ...
- 前后端分离项目,vue+uni-app+php+mysql图书购物商城小程序系统 开题报告
毕业论文 基于Vue.js图书商城小程序系统 开题报告 学 院: 专 业: 年 级: 学生姓名: 指导教师: 黄菊华 XXXX大学本科生毕业论文(设计)开题报告书 姓 名 ...
最新文章
- 深度学习的算法实践和演进
- python使用符号 表示单行注释-Python注释(多行注释和单行注释)用法详解
- 学习《apache源代码全景分析》之常用过滤器摘录
- 使用.Net6中的System.Text.Json遇到几个常见问题及解决方案
- 计算机仿真技术-基于matlab的电子信息类课程课后答案,计算机仿真技术:基于MATLAB的电子信息类课程(第4版)...
- 检测 USB 设备拨插的 C# 类库:USBClassLibrary
- SharePoint读取和设置列表栏的内容
- caffe face 实现人脸相似度识别 c++版本
- 拍照扫描身份证的识别软件SDK
- safari查看html代码,iPhone不越狱safari查看网页源代码方法
- Java 运算符 输入 分支语句
- 推荐丨全球主要城市TOD数据
- DNS云监控出现问题如何解决
- SpringBoot的热布署和多环境配置(四)
- iOS 开发者账号持有人转让最新方式
- Springboot项目install打包-某些输入文件使用了未经检查或不安全的操作。分析与解决
- Nginx+Tomcat实现负载均衡与动静分离
- JAVA 经典面试题:ES如何做到亿级数据查询毫秒级返回?
- 评价星星等级显示(包含星星对应的等级)
- C++实现声音文件的播放(OpenAL、Fmod、BASS、SFML)
热门文章
- python实现数据结构的基础
- 复联全员集结,用Python分析一下大家都pick谁?
- 初探使用iOS 7 Sprite Kit与Cocos2d开发游戏的对比
- 华容道3x3的技巧_数字华容道怎样才能有解
- 精美UI强大娱乐功能组合微信小程序源码下载,安装简单
- 剑指offer读书笔记
- 协议:TCP缓冲区滑窗拥塞控制慢启动 (建议收藏!)
- HQ-day14 HTML基础
- 【调剂】长江大学接收调剂研究生,工科,电子信息招专硕或学硕调剂生。压缩感知、深度学习方向等多个方向。...
- fastcgi php错误,FastCGI Error 0x80004005的解决办法