当前位置:科学 > 正文

Win10基于Vue.js+Django+Python3微信扫码支付流程

2023-01-31 10:55:47  来源:刘悦技术分享

之前的一篇文章: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 requestsfrom django.http import HttpResponse, HttpResponseRedirectimport randomimport timeimport hashlibimport qrcodefrom bs4 import BeautifulSoupdef 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_dictdef 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))  # 返回XMLdef 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

一望而知,我们需要调用微信的统一下单接口,文档: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_payfrom django.contrib.staticfiles.urls import staticfiles_urlpatterns# ... the rest of your URLconf goes here ...urlpatterns = [    #定义超链接路由    re_path("^static/upload/(?P<path>.*)#39;,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上的限制,所以退款流程应该会需要消息队列的介入。

关键词: Django Windows JSON ____

推荐阅读

蓝太阳什么时候出现过 蓝太阳是怎么形成的?

平常晴天的时候都是可以看见太阳的,不过我们也知道平时看到的太阳是黄色的发光发亮的球体,不过今日北京出现蓝太阳,蓝太阳是什么意思?蓝 【详细】

低碳环保节能产业是什么概念 为什么环保受到大家的重视?

低碳环保节能产业,是什么概念,怎么理解?节能环保产业是指为节约能源资源、发展循环经济和保护生态环境提供物质基础和技术支持的产业,是 【详细】

dwg文件是什么 dwg文件用什么打开?

相信很多人都不知道dwg文件用什么打开?,接下来小编就带大家介绍一些方法,大家可以了解一下。一、看图纸参见图纸DwgSeePlus是一个dwg文件 【详细】

工业革命是什么 工业革命的影响有哪些?

工业革命的影响有哪些?三次工业革命分别是什么时间?影响1、工业革命引起了生产组织形式的变化,用机器工厂制代替手工作坊。影响2 工业革命 【详细】

导电膏的作用 导电膏使用方法是什么?

电接触导电膏是由无机稠化剂稠化合成油并加有超细导电填料、抗腐蚀、抗氧化等多种添加剂精制而成的导电防腐油膏。此导电膏设计用于改善电力 【详细】

关于我们  |  联系方式  |  免责条款  |  招聘信息  |  广告服务  |  帮助中心

联系我们:85 572 98@qq.com备案号:粤ICP备18023326号-40

科技资讯网 版权所有